﻿using HARTCalibrationTool.Commands;
using HARTCalibrationTool.Commands.BatchCalibrationBoard;
using HARTCalibrationTool.Commands.HART;
using HARTCalibrationTool.Commands.HART.CustomCommands;
using HARTCalibrationTool.Commands.TwoDimensionalCMDGroup;
using HARTCalibrationTool.Observers;
using HARTCalibrationTool.SerialPortManager;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using Newtonsoft.Json;
using System.IO;
using HARTCalibrationTool.JsonFilesManager;
using MathNet.Numerics;
using NationalInstruments.Visa;
using Ivi.Visa;
using System.Text.RegularExpressions;
using HARTCalibrationTool.Commands.PressureController;
using System.Threading;
using HARTCalibrationTool.AutomaticCalibration;
using System.Drawing.Imaging;
using MathNet.Numerics.Distributions;
using nisysapi;
using HARTCalibrationTool.UI;
using OfficeOpenXml;

namespace HARTCalibrationTool
{
    public partial class MainUI : Form
    {
        private BatchCaliBoardSerialPort batchBoardSerialPort = new BatchCaliBoardSerialPort();
        private HARTSerialPort_woyatechHARTModem hARTSerialPort_woyatechModem = new HARTSerialPort_woyatechHARTModem();
        private TemperatureBoxSerialPort temperatureBoxSerialPort = new TemperatureBoxSerialPort();
        private PressureControllerSerialPort preControllerSerialPort = new PressureControllerSerialPort();

        List<(CMDsGroup, TimeSpan)> CMDsGroups = new List<(CMDsGroup, TimeSpan)>();

        private LoopGroupCMDsManager gLoopGroupCMDsManager = new LoopGroupCMDsManager();

        public static DebugLogger _logger = new DebugLogger();

        private System.Windows.Forms.Timer countDownTimer;
        private System.Windows.Forms.Timer caliTotalTimer;

        private int remainingTimeInSeconds = 0;
        private int caliTimeInSeconds = 0;

        private RetestUI retestUI = new RetestUI();

        private List<List<string>>[] retestData = new List<List<string>>[32];

        public ExcelHelper excelHelperCls = new ExcelHelper();

        public enum CollectionType
        { 
            eCollectionTypeNone = 0x00,

            eCollectionTypeUP1 = 0x01,
            eCollectionTypeDP1,

            eCollectionTypeUP2,
            eCollectionTypeDP2,

            eCollectionTypeUP3,
            eCollectionTypeDP3,

            eCollectionTypeUP4,
            eCollectionTypeDP4,

            eCollectionTypeUP5,
            eCollectionTypeDP5,

            eCollectionTypeUP6,
            eCollectionTypeDP6,

            eCollectionTypeUP7,
            eCollectionTypeDP7,

            eCollectionTypeUP8,
            eCollectionTypeDP8,

            eCollectionTypeUP9,
            eCollectionTypeDP9,
        };

        CMDsGroup CMDsGroup1 = new CMDsGroup(CMDsChlID.eChannel1);
        CMDsGroup CMDsGroup2 = new CMDsGroup(CMDsChlID.eChannel2);
        CMDsGroup CMDsGroup3 = new CMDsGroup(CMDsChlID.eChannel3);
        CMDsGroup CMDsGroup4 = new CMDsGroup(CMDsChlID.eChannel4);
        CMDsGroup CMDsGroup5 = new CMDsGroup(CMDsChlID.eChannel5);
        CMDsGroup CMDsGroup6 = new CMDsGroup(CMDsChlID.eChannel6);
        CMDsGroup CMDsGroup7 = new CMDsGroup(CMDsChlID.eChannel7);
        CMDsGroup CMDsGroup8 = new CMDsGroup(CMDsChlID.eChannel8);
        CMDsGroup CMDsGroup9 = new CMDsGroup(CMDsChlID.eChannel9);
        CMDsGroup CMDsGroup10 = new CMDsGroup(CMDsChlID.eChannel10);
        CMDsGroup CMDsGroup11 = new CMDsGroup(CMDsChlID.eChannel11);
        CMDsGroup CMDsGroup12 = new CMDsGroup(CMDsChlID.eChannel12);
        CMDsGroup CMDsGroup13 = new CMDsGroup(CMDsChlID.eChannel13);
        CMDsGroup CMDsGroup14 = new CMDsGroup(CMDsChlID.eChannel14);
        CMDsGroup CMDsGroup15 = new CMDsGroup(CMDsChlID.eChannel15);
        CMDsGroup CMDsGroup16 = new CMDsGroup(CMDsChlID.eChannel16);
        CMDsGroup CMDsGroup17 = new CMDsGroup(CMDsChlID.eChannel17);
        CMDsGroup CMDsGroup18 = new CMDsGroup(CMDsChlID.eChannel18);
        CMDsGroup CMDsGroup19 = new CMDsGroup(CMDsChlID.eChannel19);
        CMDsGroup CMDsGroup20 = new CMDsGroup(CMDsChlID.eChannel20);
        CMDsGroup CMDsGroup21 = new CMDsGroup(CMDsChlID.eChannel21);
        CMDsGroup CMDsGroup22 = new CMDsGroup(CMDsChlID.eChannel22);
        CMDsGroup CMDsGroup23 = new CMDsGroup(CMDsChlID.eChannel23);
        CMDsGroup CMDsGroup24 = new CMDsGroup(CMDsChlID.eChannel24);
        CMDsGroup CMDsGroup25 = new CMDsGroup(CMDsChlID.eChannel25);
        CMDsGroup CMDsGroup26 = new CMDsGroup(CMDsChlID.eChannel26);
        CMDsGroup CMDsGroup27 = new CMDsGroup(CMDsChlID.eChannel27);
        CMDsGroup CMDsGroup28 = new CMDsGroup(CMDsChlID.eChannel28);
        CMDsGroup CMDsGroup29 = new CMDsGroup(CMDsChlID.eChannel29);
        CMDsGroup CMDsGroup30 = new CMDsGroup(CMDsChlID.eChannel30);
        CMDsGroup CMDsGroup31 = new CMDsGroup(CMDsChlID.eChannel31);
        CMDsGroup CMDsGroup32 = new CMDsGroup(CMDsChlID.eChannel32);

        CMDsGroup[] gCMSsGroupsAry = null;
        CheckBox[] gCheckBoxDevsSelectedAry = null;

        Panel[] gIndicatorAry = null;

        private const double _GroupsIntervalTimeSeconds = 0.5;
        private const double _CommandsIntervalTimeSeconds = 0.5;

        private string _jsonFolderPath = null;

        // 压力曲线 <("变送器x", 温度点)，系数[5]>
        private Dictionary<(string, string), double[]> _pressureCurveCoefficient = new Dictionary<(string, string), double[]>();
        // 温度曲线 <"变送器x", double[4]>
        private Dictionary<string, double[]> _temperatureCurveCoefficient = new Dictionary<string, double[]>();

        private static JsonPressureTemperatureCurveCof _jsonPreAndTempCurveCof = new JsonPressureTemperatureCurveCof();

        private IMessageBasedSession _visaSession;

        private RadioButton _previousRadioButton;
        private bool isProcessingEvent = false;

        private bool _bConfigInfoIsOK = false;

        private string _exePath = AppDomain.CurrentDomain.BaseDirectory;

        private CollectionType _curCollectionType = CollectionType.eCollectionTypeNone;
        private string _curCollectionTemperature = null;

        private string _excelFilePath = null;

        public MainUI()
        {
            InitializeComponent();
        }

        private void MainUI_Load(object sender, EventArgs e)
        {
            ToolStripProgressBarResize();

            UpdateSerialNames(batchBoardSerialPort);
            UpdateSerialNames(hARTSerialPort_woyatechModem);
            UpdateSerialNames(temperatureBoxSerialPort);
            UpdateSerialNames(preControllerSerialPort);

            AdjustListViewColumnWidths();

            SerialPortsBase.SetDebugMessageContrl(this.txtBoxDebugInfo);

            this.cboxCMDsSel.SelectedIndex = 0;

            // Init ListView
            foreach (ListViewItem item in this.listView1.Items)
            {
                for (int i = 0; i < this.listView1.Columns.Count; i++)
                {
                    item.SubItems.Add("");
                }
            }

            coboxTempPointNum.SelectedIndex = 0;
            cboxConfigRange.SelectedIndex = 0;
            comboxCurrentMode.SelectedIndex = 0;
            cboxTemperaturePoints.SelectedIndex = 0;
            cboxPreFitDegree.SelectedIndex = 0;
            cboxTempFitDegree.SelectedIndex = 0;
            cboxPressurePoints.SelectedIndex = 0;
            cboxSensorRange.SelectedIndex = 0;
            cboxRGBOpSel.SelectedIndex = 0;
            cboxPreCtrlUnit.SelectedIndex = 0;
            cboxPressureThresholdVal.SelectedIndex = 0;
            cboxKeepingTime.SelectedIndex = 2;
            cboxStabPreTime.SelectedIndex = 2;

            _previousRadioButton = radBtnTemp1;

            gCheckBoxDevsSelectedAry = new CheckBox[32]
            {
                this.chkBoxTransfer1, this.chkBoxTransfer2, this.chkBoxTransfer3, this.chkBoxTransfer4, this.chkBoxTransfer5,
                this.chkBoxTransfer6, this.chkBoxTransfer7, this.chkBoxTransfer8, this.chkBoxTransfer9, this.chkBoxTransfer10,
                this.chkBoxTransfer11, this.chkBoxTransfer12, this.chkBoxTransfer13, this.chkBoxTransfer14, this.chkBoxTransfer15,
                this.chkBoxTransfer16, this.chkBoxTransfer17, this.chkBoxTransfer18, this.chkBoxTransfer19, this.chkBoxTransfer20,
                this.chkBoxTransfer21, this.chkBoxTransfer22, this.chkBoxTransfer23, this.chkBoxTransfer24, this.chkBoxTransfer25,
                this.chkBoxTransfer26, this.chkBoxTransfer27, this.chkBoxTransfer28, this.chkBoxTransfer29, this.chkBoxTransfer30,
                this.chkBoxTransfer31, this.chkBoxTransfer32
            };

            gCMSsGroupsAry = new CMDsGroup[32]
            {
                CMDsGroup1, CMDsGroup2, CMDsGroup3, CMDsGroup4, CMDsGroup5, CMDsGroup6, CMDsGroup7, CMDsGroup8, CMDsGroup9, CMDsGroup10,
                CMDsGroup11, CMDsGroup12, CMDsGroup13, CMDsGroup14, CMDsGroup15, CMDsGroup16, CMDsGroup17, CMDsGroup18, CMDsGroup19, CMDsGroup20,
                CMDsGroup21, CMDsGroup22, CMDsGroup23, CMDsGroup24, CMDsGroup25, CMDsGroup26, CMDsGroup27, CMDsGroup28, CMDsGroup29, CMDsGroup30,
                CMDsGroup31, CMDsGroup32
            };

            gIndicatorAry = new Panel[32]
            {
                panelIndicatorLight1, panelIndicatorLight2, panelIndicatorLight3, panelIndicatorLight4, panelIndicatorLight5,
                panelIndicatorLight6, panelIndicatorLight7, panelIndicatorLight8, panelIndicatorLight9, panelIndicatorLight10,
                panelIndicatorLight11, panelIndicatorLight12, panelIndicatorLight13, panelIndicatorLight14, panelIndicatorLight15,
                panelIndicatorLight16, panelIndicatorLight17, panelIndicatorLight18, panelIndicatorLight19, panelIndicatorLight20,
                panelIndicatorLight21, panelIndicatorLight22, panelIndicatorLight23, panelIndicatorLight24, panelIndicatorLight25,
                panelIndicatorLight26, panelIndicatorLight27, panelIndicatorLight28, panelIndicatorLight29, panelIndicatorLight30,
                panelIndicatorLight31, panelIndicatorLight32,
            };

            countDownTimer = new System.Windows.Forms.Timer();
            countDownTimer.Interval = 1000; // ms
            countDownTimer.Tick += CountDownTimer_Tick;

            caliTotalTimer = new System.Windows.Forms.Timer();
            caliTotalTimer.Interval = 1000; // ms
            caliTotalTimer.Tick += CaliTotalTimer_Tick;
        }

        private void MainUI_SizeChanged(object sender, EventArgs e)
        {
            ToolStripProgressBarResize();
            AdjustListViewColumnWidths();
        }
        private void ToolStripProgressBarResize()
        {
            toolStripProgressBar.Width = statusStrip.Width - 5;
        }

        private void ListViewTransducerInfoClr(ListView listView)
        {
            foreach (ListViewItem item in listView.Items)
            {
                for (int i = 1; i < listView.Columns.Count; i++)
                {
                    item.SubItems[i].Text = "";
                }
            }
        }

        private void labelAll_Click(object sender, EventArgs e)
        {
            chkBoxTransfer2.Checked = true;
            chkBoxTransfer17.Checked = true;
            chkBoxTransfer18.Checked = true;
            chkBoxTransfer19.Checked = true;
            chkBoxTransfer5.Checked = true;
            chkBoxTransfer21.Checked = true;
            chkBoxTransfer7.Checked = true;
            chkBoxTransfer23.Checked = true;
            chkBoxTransfer9.Checked = true;
            chkBoxTransfer25.Checked = true;
            chkBoxTransfer26.Checked = true;
            chkBoxTransfer27.Checked = true;
            chkBoxTransfer13.Checked = true;
            chkBoxTransfer29.Checked = true;
            chkBoxTransfer15.Checked = true;
            chkBoxTransfer31.Checked = true;
            chkBoxTransfer1.Checked = true;
            chkBoxTransfer3.Checked = true;
            chkBoxTransfer4.Checked = true;
            chkBoxTransfer20.Checked = true;
            chkBoxTransfer6.Checked = true;
            chkBoxTransfer22.Checked = true;
            chkBoxTransfer8.Checked = true;
            chkBoxTransfer24.Checked = true;
            chkBoxTransfer10.Checked = true;
            chkBoxTransfer11.Checked = true;
            chkBoxTransfer12.Checked = true;
            chkBoxTransfer28.Checked = true;
            chkBoxTransfer14.Checked = true;
            chkBoxTransfer30.Checked = true;
            chkBoxTransfer16.Checked = true;
            chkBoxTransfer32.Checked = true;
        }

        private void labelNone_Click(object sender, EventArgs e)
        {
            chkBoxTransfer2.Checked = false;
            chkBoxTransfer17.Checked = false;
            chkBoxTransfer18.Checked = false;
            chkBoxTransfer19.Checked = false;
            chkBoxTransfer5.Checked = false;
            chkBoxTransfer21.Checked = false;
            chkBoxTransfer7.Checked = false;
            chkBoxTransfer23.Checked = false;
            chkBoxTransfer9.Checked = false;
            chkBoxTransfer25.Checked = false;
            chkBoxTransfer26.Checked = false;
            chkBoxTransfer27.Checked = false;
            chkBoxTransfer13.Checked = false;
            chkBoxTransfer29.Checked = false;
            chkBoxTransfer15.Checked = false;
            chkBoxTransfer31.Checked = false;
            chkBoxTransfer1.Checked = false;
            chkBoxTransfer3.Checked = false;
            chkBoxTransfer4.Checked = false;
            chkBoxTransfer20.Checked = false;
            chkBoxTransfer6.Checked = false;
            chkBoxTransfer22.Checked = false;
            chkBoxTransfer8.Checked = false;
            chkBoxTransfer24.Checked = false;
            chkBoxTransfer10.Checked = false;
            chkBoxTransfer11.Checked = false;
            chkBoxTransfer12.Checked = false;
            chkBoxTransfer28.Checked = false;
            chkBoxTransfer14.Checked = false;
            chkBoxTransfer30.Checked = false;
            chkBoxTransfer16.Checked = false;
            chkBoxTransfer32.Checked = false;
        }

        private void UpdateSerialNames(SerialPortsBase serialPort)
        { 
            string[] portName = SerialPort.GetPortNames();

            if (portName == null || portName.Length == 0)
            {
                return;
            }

            if (serialPort is BatchCaliBoardSerialPort)
            {
                this.cboxBatchBoardSerialPort.Items.Clear();
                this.cboxBatchBoardSerialPort.Items.AddRange(portName);
                this.cboxBatchBoardSerialPort.SelectedIndex = 0;
            }
            else if (serialPort is HARTSerialPort)
            {
                this.cboxHARTSerialPort.Items.Clear();
                this.cboxHARTSerialPort.Items.AddRange(portName);
                this.cboxHARTSerialPort.SelectedIndex = 0;
            }
            else if (serialPort is TemperatureBoxSerialPort)
            {
                this.cboxTempBoxSPortSel.Items.Clear();
                this.cboxTempBoxSPortSel.Items.AddRange(portName);
                this.cboxTempBoxSPortSel.SelectedIndex = 0;
            }
            else if (serialPort is PressureControllerSerialPort)
            {
                this.cboxPreControlerSerialPort.Items.Clear();
                this.cboxPreControlerSerialPort.Items.AddRange(portName);
                this.cboxPreControlerSerialPort.SelectedIndex = 0;
            }
        }

        private void btnBatchBoardSerialPortOpen_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(this.cboxBatchBoardSerialPort.Text))
            {
                return;
            }

            if (batchBoardSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("批量标定板串口已打开。");
                return;
            }

            if (batchBoardSerialPort.Open(this.cboxBatchBoardSerialPort.Text))
            {
                PrintfMsg("批量标定板串口打开成功。");
                this.panelBatchBoardSerialIndicator.BackColor = Color.IndianRed;
            }
            else
            {
                PrintfMsg("批量标定板串口打开失败。");
                this.panelBatchBoardSerialIndicator.BackColor = Color.DarkGray;
            }
        }

        private void btnBatchBoardSerialPortClose_Click(object sender, EventArgs e)
        {
            if (batchBoardSerialPort.SerialPortIsOpen())
            {
                if (batchBoardSerialPort.Close())
                {
                    PrintfMsg("批量标定板串口关闭成功。");
                    this.panelBatchBoardSerialIndicator.BackColor = Color.DarkGray;
                }
            }
            else
            {
                PrintfMsg("批量标定板串口已关闭。");
            }    
        }

        private void PrintfMsg(string msg)
        {
            this.txtBoxDebugInfo.AppendText("[" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "]: " + msg + "\r\n");
        }

        private void AdjustListViewColumnWidths()
        {
            int totalWidth = listView1.ClientSize.Width;        
            int columnWidth = totalWidth / listView1.Columns.Count;     

            foreach (ColumnHeader column in listView1.Columns)
            {
                column.Width = columnWidth;
            }

            AdjustListViewColumnWidthFitInfo();
            AdjustListViewColumnWidthFitData();
        }

        private void AdjustListViewColumnWidthFitInfo()
        {
            int totalWidth1 = listViewSrcData.ClientSize.Width;
            int columnWidth1 = totalWidth1 / (listViewSrcData.Columns.Count - 1);

            listViewSrcData.Columns[0].Width = 30;
            for (byte i = 1; i < listViewSrcData.Columns.Count; i++)
            {
                listViewSrcData.Columns[i].Width = columnWidth1;
            }
        }
        
        private void AdjustListViewColumnWidthFitData()
        {
            int totalWidth1 = listViewFitData.ClientSize.Width;
            int columnWidth1 = totalWidth1 / (listViewFitData.Columns.Count - 2);

            listViewFitData.Columns[0].Width = 40;
            listViewFitData.Columns[1].Width = 80;

            for (byte i = 2; i < listViewFitData.Columns.Count; i++)
            {
                listViewFitData.Columns[i].Width = (columnWidth1 - 40);
            }
        }

        private void btnTransfers_Click(object sender, EventArgs e)
        {
            if (batchBoardSerialPort.SerialPortIsOpen() == false)
            {
                SerialPortsBase.PrintMessage("批量板串口未打开！");
                return;
            }

            if((this.cboxCMDsSel.Text != "切换HART通道") && (this.cboxCMDsSel.Text != "切换万用表通道"))
            {
                if (hARTSerialPort_woyatechModem.SerialPortIsOpen() == false)
                {
                    SerialPortsBase.PrintMessage("HART串口未打开！");
                    return;
                }
            }

            if (CommandsBase.bHasCMDExecuting == true)
            {
                SerialPortsBase.PrintMessage("有命令正在执行，请稍等！");
                return;
            }

            CommandsBase.bHasCMDExecuting = true;

            switch (this.cboxCMDsSel.Text)
            {
                case "切换HART通道":
                    CommandSwitchHARTChl(sender);
                    break;
                case "切换万用表通道":
                    CommandSwitchMeterChl(sender);
                    break;
                case "HART#0读标识码":
                    CommandHART0(sender);
                    break;
                case "查找地址0":
                    CommandSearchAddr0(sender);
                    break;
                case "轮询0～15":
                    CommandPollingAddress0To15(sender);
                    break;
                case "获取压力拟合值":
                    CommandGetPressureFitData(sender);
                    break;
                case "获取温度拟合值":
                    CommandGetTemperatureFitData(sender);
                    break;
                case "获取校准标志":
                    CommandGetCalibrationFlag(sender);
                    break;
                case "获取电流值":
                    CommandGetCurrentValue(sender);
                    break;
                case "获取多个数据":
                    CommandGetMultiData(sender);
                    break;
                case "获取设备当前压力值":
                    CommandGetPressure(sender);
                    break;
                case "获取设备当前温度值":
                    CommandGetTemperature(sender);
                    break;

                default: break;
            }
        }

        private void btnHARTSerialPortOpen_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(this.cboxHARTSerialPort.Text))
            {
                return;
            }

            if (hARTSerialPort_woyatechModem.SerialPortIsOpen())
            {
                PrintfMsg("HART串口已打开。");
                return;
            }

            if (hARTSerialPort_woyatechModem.Open(this.cboxHARTSerialPort.Text))
            {
                PrintfMsg("HART串口打开成功。");
                this.panelHARTSerialPort.BackColor = Color.IndianRed;
            }
            else
            {
                PrintfMsg("HART串口打开失败。");
                this.panelHARTSerialPort.BackColor = Color.DarkGray;
            }
        }

        private void btnHARTSerialPortClose_Click(object sender, EventArgs e)
        {
            if (hARTSerialPort_woyatechModem.SerialPortIsOpen())
            {
                if (hARTSerialPort_woyatechModem.Close())
                {
                    PrintfMsg("HART串口关闭成功。");
                    this.panelHARTSerialPort.BackColor = Color.DarkGray;
                }
            }
            else
            {
                PrintfMsg("HART串口已关闭。");
            }
        }
        
        private void panelBatchBoardSerialIndicator_Click(object sender, EventArgs e)
        {
            UpdateSerialNames(batchBoardSerialPort);
        }

        private void panelHARTSerialIndicator_Click(object sender, EventArgs e)
        {
            UpdateSerialNames(hARTSerialPort_woyatechModem);
        }

        private async void CommandSwitchHARTChl(object sender)
        {
            CMDsGroup currentGroup = GetCurrentGroups(sender);

            if (currentGroup == null)
            {
                return;
            }

            CMDsGroups.Clear();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl");

            CloseAllPanelsIndicatorLight();

            batchBoardSerialPort.RegisterObservers(BatchCaliBoardObserversInfo.info["HART Channel Switch"], new PanelUpdater(GetIndicatorLight(sender)));

            currentGroup.AddCommands(
                new List<(CommandsBase, TimeSpan)>()
                {
                    (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                }
            );

            CMDsGroups.Add((currentGroup, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private async void CommandSwitchMeterChl(object sender)
        {
            CMDsGroup currentGroup = GetCurrentGroups(sender);

            if (currentGroup == null)
            {
                return;
            }

            CMDsGroups.Clear();

            BatchCaliBoardCMDsSwitchMultiMeterChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchMultiMeterChlCMD(batchBoardSerialPort, "Traversal Switch Chl");

            CloseAllPanelsIndicatorLight();

            batchBoardSerialPort.RegisterObservers(BatchCaliBoardObserversInfo.info["Meter Channel Switch"], new PanelUpdater(GetIndicatorLight(sender)));

            currentGroup.AddCommands(
                new List<(CommandsBase, TimeSpan)>()
                {
                    (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                }
            );

            CMDsGroups.Add((currentGroup, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private async void CommandHART0(object sender)
        {
            CMDsGroup currentGroup = GetCurrentGroups(sender);

            if (currentGroup == null)
            {
                return;
            }

            CMDsGroups.Clear();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl");
            HART0ReadUniqueIdentifier hHARTCMD0 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "Groups HART#0");

            CloseAllPanelsIndicatorLight();

            batchBoardSerialPort.RegisterObservers(BatchCaliBoardObserversInfo.info["HART Channel Switch"], new PanelUpdater(GetIndicatorLight(sender)));
            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #0 All"], new ListViewUpdater(this.listView1));

            currentGroup.AddCommands(
                new List<(CommandsBase, TimeSpan)>()
                {
                    (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (hHARTCMD0, TimeSpan.FromSeconds(0)),
                }
            );

            CMDsGroups.Add((currentGroup, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private async void CommandSearchAddr0(object sender)
        {
            CMDsGroup currentGroup = GetCurrentGroups(sender);

            if (currentGroup == null)
            {
                return;
            }

            CMDsGroups.Clear();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl");
            // HART #0
            HART0ReadUniqueIdentifier hHARTCMD0 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "Groups HART#0");
            // HART #12
            HART12ReadMessage hART12ReadMessage = new HART12ReadMessage(hARTSerialPort_woyatechModem, "HART#12");
            // HART #14
            HART14ReadPVTransducerInfo hART14ReadPVTransducerInfo = new HART14ReadPVTransducerInfo(hARTSerialPort_woyatechModem, "HART#14");
            // HART #15
            HART15ReadDeviceInfo hART15ReadDeviceInfo = new HART15ReadDeviceInfo(hARTSerialPort_woyatechModem, "HART#15");

            CloseAllPanelsIndicatorLight();

            batchBoardSerialPort.RegisterObservers(BatchCaliBoardObserversInfo.info["HART Channel Switch"], new PanelUpdater(GetIndicatorLight(sender)));
            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #0 All"], new ListViewUpdater(this.listView1));

            currentGroup.AddCommands(
                new List<(CommandsBase, TimeSpan)>()
                {
                    (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (hHARTCMD0, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (hART12ReadMessage, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (hART14ReadPVTransducerInfo, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (hART15ReadDeviceInfo, TimeSpan.FromSeconds(0)),
                }
            );

            CMDsGroups.Add((currentGroup, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private async void CommandPollingAddress0To15(object sender)
        {
            CMDsGroup currentGroup = GetCurrentGroups(sender);

            if (currentGroup == null)
            {
                return;
            }

            CMDsGroups.Clear();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl");

            HART0ReadUniqueIdentifier CMD0 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "HART#0 Polling Addr0");
            CMD0.SetPollingAddrInCommandCode(0x00);

            HART0ReadUniqueIdentifier CMD1 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "HART#0 Polling Addr1");
            CMD1.SetPollingAddrInCommandCode(0x01);

            HART0ReadUniqueIdentifier CMD2 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "HART#0 Polling Addr2");
            CMD2.SetPollingAddrInCommandCode(0x02);

            HART0ReadUniqueIdentifier CMD3 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "HART#0 Polling Addr3");
            CMD3.SetPollingAddrInCommandCode(0x03);

            HART0ReadUniqueIdentifier CMD4 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "HART#0 Polling Addr4");
            CMD4.SetPollingAddrInCommandCode(0x04);

            HART0ReadUniqueIdentifier CMD5 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "HART#0 Polling Addr5");
            CMD5.SetPollingAddrInCommandCode(0x05);

            HART0ReadUniqueIdentifier CMD6 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "HART#0 Polling Addr6");
            CMD6.SetPollingAddrInCommandCode(0x06);

            HART0ReadUniqueIdentifier CMD7 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "HART#0 Polling Addr7");
            CMD7.SetPollingAddrInCommandCode(0x07);

            HART0ReadUniqueIdentifier CMD8 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "HART#0 Polling Addr8");
            CMD8.SetPollingAddrInCommandCode(0x08);

            HART0ReadUniqueIdentifier CMD9 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "HART#0 Polling Addr9");
            CMD9.SetPollingAddrInCommandCode(0x09);

            HART0ReadUniqueIdentifier CMD10 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "HART#0 Polling Addr10");
            CMD10.SetPollingAddrInCommandCode(0x0A);

            HART0ReadUniqueIdentifier CMD11 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "HART#0 Polling Addr11");
            CMD11.SetPollingAddrInCommandCode(0x0B);

            HART0ReadUniqueIdentifier CMD12 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "HART#0 Polling Addr12");
            CMD12.SetPollingAddrInCommandCode(0x0C);

            HART0ReadUniqueIdentifier CMD13 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "HART#0 Polling Addr13");
            CMD13.SetPollingAddrInCommandCode(0x0D);

            HART0ReadUniqueIdentifier CMD14 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "HART#0 Polling Addr14");
            CMD14.SetPollingAddrInCommandCode(0x0E);

            HART0ReadUniqueIdentifier CMD15 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "HART#0 Polling Addr15");
            CMD15.SetPollingAddrInCommandCode(0x0F);

            CloseAllPanelsIndicatorLight();

            batchBoardSerialPort.RegisterObservers(BatchCaliBoardObserversInfo.info["HART Channel Switch"], new PanelUpdater(GetIndicatorLight(sender)));
            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #0 All"], new ListViewUpdater(this.listView1));

            currentGroup.AddCommands(
                new List<(CommandsBase, TimeSpan)>()
                {
                    (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (CMD0, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (CMD1, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (CMD2, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (CMD3, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (CMD4, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (CMD5, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (CMD6, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (CMD7, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (CMD8, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (CMD9, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (CMD10, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (CMD11, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (CMD12, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (CMD13, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (CMD14, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (CMD15, TimeSpan.FromSeconds(0)),
                }
            );

            CMDsGroups.Add((currentGroup, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private async void CommandGetPressureFitData(object sender)
        {
            CMDsGroup currentGroup = GetCurrentGroups(sender);

            if (currentGroup == null)
            {
                return;
            }

            CMDsGroups.Clear();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl");

            HART135CustomCommand hART135CustomCommand = new HART135CustomCommand(hARTSerialPort_woyatechModem, "HART#135#1", CustomCommandsBase.GETPREADVALUE);

            batchBoardSerialPort.RegisterObservers(BatchCaliBoardObserversInfo.info["HART Channel Switch"], new PanelUpdater(GetIndicatorLight(sender)));

            CloseAllPanelsIndicatorLight();

            currentGroup.AddCommands(
                new List<(CommandsBase, TimeSpan)>()
                {
                    (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (hART135CustomCommand, TimeSpan.FromSeconds(0)),
                }
            );

            CMDsGroups.Add((currentGroup, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private async void CommandGetTemperatureFitData(object sender)
        {
            CMDsGroup currentGroup = GetCurrentGroups(sender);

            if (currentGroup == null)
            {
                return;
            }

            CMDsGroups.Clear();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl");

            HART135CustomCommand hART135CustomCommand = new HART135CustomCommand(hARTSerialPort_woyatechModem, "HART#135#2", CustomCommandsBase.GETTMPADVALUE);

            batchBoardSerialPort.RegisterObservers(BatchCaliBoardObserversInfo.info["HART Channel Switch"], new PanelUpdater(GetIndicatorLight(sender)));

            CloseAllPanelsIndicatorLight();

            currentGroup.AddCommands(
                new List<(CommandsBase, TimeSpan)>()
                {
                    (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (hART135CustomCommand, TimeSpan.FromSeconds(0)),
                }
            );

            CMDsGroups.Add((currentGroup, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private async void CommandGetCalibrationFlag(object sender)
        {
            CMDsGroup currentGroup = GetCurrentGroups(sender);

            if (currentGroup == null)
            {
                return;
            }

            CMDsGroups.Clear();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl");

            HART135CustomCommand hART135CustomCommand = new HART135CustomCommand(hARTSerialPort_woyatechModem, "HART#135#3", CustomCommandsBase.GET_CAL_FLG);

            batchBoardSerialPort.RegisterObservers(BatchCaliBoardObserversInfo.info["HART Channel Switch"], new PanelUpdater(GetIndicatorLight(sender)));

            CloseAllPanelsIndicatorLight();

            currentGroup.AddCommands(
                new List<(CommandsBase, TimeSpan)>()
                {
                    (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (hART135CustomCommand, TimeSpan.FromSeconds(0)),
                }
            );

            CMDsGroups.Add((currentGroup, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private async void CommandGetCurrentValue(object sender)
        {
            CMDsGroup currentGroup = GetCurrentGroups(sender);

            if (currentGroup == null)
            {
                return;
            }

            CMDsGroups.Clear();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl");

            HART135CustomCommand hART135CustomCommand = new HART135CustomCommand(hARTSerialPort_woyatechModem, "HART#135#4", CustomCommandsBase.GET_CUR);

            batchBoardSerialPort.RegisterObservers(BatchCaliBoardObserversInfo.info["HART Channel Switch"], new PanelUpdater(GetIndicatorLight(sender)));

            CloseAllPanelsIndicatorLight();

            currentGroup.AddCommands(
                new List<(CommandsBase, TimeSpan)>()
                {
                    (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (hART135CustomCommand, TimeSpan.FromSeconds(0)),
                }
            );

            CMDsGroups.Add((currentGroup, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private async void CommandGetMultiData(object sender)
        {
            CMDsGroup currentGroup = GetCurrentGroups(sender);

            if (currentGroup == null)
            {
                return;
            }

            CMDsGroups.Clear();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl");

            HART135CustomCommand hART135CustomCommand = new HART135CustomCommand(hARTSerialPort_woyatechModem, "HART#135#08", CustomCommandsBase.GET_INFO);

            batchBoardSerialPort.RegisterObservers(BatchCaliBoardObserversInfo.info["HART Channel Switch"], new PanelUpdater(GetIndicatorLight(sender)));

            CloseAllPanelsIndicatorLight();

            currentGroup.AddCommands(
                new List<(CommandsBase, TimeSpan)>()
                {
                    (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (hART135CustomCommand, TimeSpan.FromSeconds(0)),
                }
            );

            CMDsGroups.Add((currentGroup, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private async void CommandGetPressure(object sender)
        {
            CMDsGroup currentGroup = GetCurrentGroups(sender);

            if (currentGroup == null)
            {
                return;
            }

            CMDsGroups.Clear();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl");

            HART135CustomCommand hART135CustomCommand = new HART135CustomCommand(hARTSerialPort_woyatechModem, "HART#135#10", CustomCommandsBase.GETPREVALUE);

            batchBoardSerialPort.RegisterObservers(BatchCaliBoardObserversInfo.info["HART Channel Switch"], new PanelUpdater(GetIndicatorLight(sender)));

            CloseAllPanelsIndicatorLight();

            currentGroup.AddCommands(
                new List<(CommandsBase, TimeSpan)>()
                {
                    (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (hART135CustomCommand, TimeSpan.FromSeconds(0)),
                }
            );

            CMDsGroups.Add((currentGroup, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private async void CommandGetTemperature(object sender)
        {
            CMDsGroup currentGroup = GetCurrentGroups(sender);

            if (currentGroup == null)
            {
                return;
            }

            CMDsGroups.Clear();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl");

            HART135CustomCommand hART135CustomCommand = new HART135CustomCommand(hARTSerialPort_woyatechModem, "HART#135#20", CustomCommandsBase.GETTEMPVALUE);

            batchBoardSerialPort.RegisterObservers(BatchCaliBoardObserversInfo.info["HART Channel Switch"], new PanelUpdater(GetIndicatorLight(sender)));

            CloseAllPanelsIndicatorLight();

            currentGroup.AddCommands(
                new List<(CommandsBase, TimeSpan)>()
                {
                    (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                    (hART135CustomCommand, TimeSpan.FromSeconds(0)),
                }
            );

            CMDsGroups.Add((currentGroup, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private Panel GetIndicatorLight(object sender)
        {
            if (sender == btnTransfer1)
            {
                return this.panelIndicatorLight1;
            }
            else if (sender == btnTransfer17)
            {
                return this.panelIndicatorLight17;
            }
            else if (sender == btnTransfer3)
            {
                return this.panelIndicatorLight3;
            }
            else if (sender == btnTransfer4)
            {
                return this.panelIndicatorLight4;
            }
            else if (sender == btnTransfer20)
            {
                return this.panelIndicatorLight20;
            }
            else if (sender == btnTransfer6)
            {
                return this.panelIndicatorLight6;
            }
            else if (sender == btnTransfer7)
            {
                return this.panelIndicatorLight7;
            }
            else if (sender == btnTransfer8)
            {
                return this.panelIndicatorLight8;
            }
            else if (sender == btnTransfer9)
            {
                return this.panelIndicatorLight9;
            }
            else if (sender == btnTransfer10)
            {
                return this.panelIndicatorLight10;
            }
            else if (sender == btnTransfer11)
            {
                return this.panelIndicatorLight11;
            }
            else if (sender == btnTransfer12)
            {
                return this.panelIndicatorLight12;
            }
            else if (sender == btnTransfer13)
            {
                return this.panelIndicatorLight13;
            }
            else if (sender == btnTransfer14)
            {
                return this.panelIndicatorLight14;
            }
            else if (sender == btnTransfer15)
            {
                return this.panelIndicatorLight15;
            }
            else if (sender == btnTransfer16)
            {
                return this.panelIndicatorLight16;
            }
            else if (sender == btnTransfer2)
            {
                return this.panelIndicatorLight2;
            }
            else if (sender == btnTransfer18)
            {
                return this.panelIndicatorLight18;
            }
            else if (sender == btnTransfer19)
            {
                return this.panelIndicatorLight19;
            }
            else if (sender == btnTransfer5)
            {
                return this.panelIndicatorLight5;
            }
            else if (sender == btnTransfer21)
            {
                return this.panelIndicatorLight21;
            }
            else if (sender == btnTransfer22)
            {
                return this.panelIndicatorLight22;
            }
            else if (sender == btnTransfer23)
            {
                return this.panelIndicatorLight23;
            }
            else if (sender == btnTransfer24)
            {
                return this.panelIndicatorLight24;
            }
            else if (sender == btnTransfer25)
            {
                return this.panelIndicatorLight25;
            }
            else if (sender == btnTransfer26)
            {
                return this.panelIndicatorLight26;
            }
            else if (sender == btnTransfer27)
            {
                return this.panelIndicatorLight27;
            }
            else if (sender == btnTransfer28)
            {
                return this.panelIndicatorLight28;
            }
            else if (sender == btnTransfer29)
            {
                return this.panelIndicatorLight29;
            }
            else if (sender == btnTransfer30)
            {
                return this.panelIndicatorLight30;
            }
            else if (sender == btnTransfer31)
            {
                return this.panelIndicatorLight31;
            }
            else if (sender == btnTransfer32)
            {
                return this.panelIndicatorLight32;
            }
            else
            {
                return null;
            }
        }

        private CMDsGroup GetCurrentGroups(object sender)
        {
            if (sender == btnTransfer1)
            {
                return CMDsGroup1;
            }
            else if (sender == btnTransfer2)
            {
                return CMDsGroup2;
            }
            else if (sender == btnTransfer3)
            {
                return CMDsGroup3;
            }
            else if (sender == btnTransfer4)
            {
                return CMDsGroup4;
            }
            else if (sender == btnTransfer5)
            {
                return CMDsGroup5;
            }
            else if (sender == btnTransfer6)
            {
                return CMDsGroup6;
            }
            else if (sender == btnTransfer7)
            {
                return CMDsGroup7;
            }
            else if (sender == btnTransfer8)
            {
                return CMDsGroup8;
            }
            else if (sender == btnTransfer9)
            {
                return CMDsGroup9;
            }
            else if (sender == btnTransfer10)
            {
                return CMDsGroup10;
            }
            else if (sender == btnTransfer11)
            {
                return CMDsGroup11;
            }
            else if (sender == btnTransfer12)
            {
                return CMDsGroup12;
            }
            else if (sender == btnTransfer13)
            {
                return CMDsGroup13;
            }
            else if (sender == btnTransfer14)
            {
                return CMDsGroup14;
            }
            else if (sender == btnTransfer15)
            {
                return CMDsGroup15;
            }
            else if (sender == btnTransfer16)
            {
                return CMDsGroup16;
            }
            else if (sender == btnTransfer17)
            {
                return CMDsGroup17;
            }
            else if (sender == btnTransfer18)
            {
                return CMDsGroup18;
            }
            else if (sender == btnTransfer19)
            {
                return CMDsGroup19;
            }
            else if (sender == btnTransfer20)
            {
                return CMDsGroup20;
            }
            else if (sender == btnTransfer21)
            {
                return CMDsGroup21;
            }
            else if (sender == btnTransfer22)
            {
                return CMDsGroup22;
            }
            else if (sender == btnTransfer23)
            {
                return CMDsGroup23;
            }
            else if (sender == btnTransfer24)
            {
                return CMDsGroup24;
            }
            else if (sender == btnTransfer25)
            {
                return CMDsGroup25;
            }
            else if (sender == btnTransfer26)
            {
                return CMDsGroup26;
            }
            else if (sender == btnTransfer27)
            {
                return CMDsGroup27;
            }
            else if (sender == btnTransfer28)
            {
                return CMDsGroup28;
            }
            else if (sender == btnTransfer29)
            {
                return CMDsGroup29;
            }
            else if (sender == btnTransfer30)
            {
                return CMDsGroup30;
            }
            else if (sender == btnTransfer31)
            {
                return CMDsGroup31;
            }
            else if (sender == btnTransfer32)
            {
                return CMDsGroup32;
            }
            else
            {
                return null;
            }
        }

        private void CloseAllPanelsIndicatorLight()
        {
            this.panelIndicatorLight1.BackColor = Color.DarkGray;
            this.panelIndicatorLight17.BackColor = Color.DarkGray;
            this.panelIndicatorLight3.BackColor = Color.DarkGray;
            this.panelIndicatorLight4.BackColor = Color.DarkGray;
            this.panelIndicatorLight20.BackColor = Color.DarkGray;
            this.panelIndicatorLight6.BackColor = Color.DarkGray;
            this.panelIndicatorLight7.BackColor = Color.DarkGray;
            this.panelIndicatorLight8.BackColor = Color.DarkGray;
            this.panelIndicatorLight9.BackColor = Color.DarkGray;
            this.panelIndicatorLight10.BackColor = Color.DarkGray;
            this.panelIndicatorLight11.BackColor = Color.DarkGray;
            this.panelIndicatorLight12.BackColor = Color.DarkGray;
            this.panelIndicatorLight13.BackColor = Color.DarkGray;
            this.panelIndicatorLight14.BackColor = Color.DarkGray;
            this.panelIndicatorLight15.BackColor = Color.DarkGray;
            this.panelIndicatorLight16.BackColor = Color.DarkGray;
            this.panelIndicatorLight2.BackColor = Color.DarkGray;
            this.panelIndicatorLight18.BackColor = Color.DarkGray;
            this.panelIndicatorLight19.BackColor = Color.DarkGray;
            this.panelIndicatorLight5.BackColor = Color.DarkGray;
            this.panelIndicatorLight21.BackColor = Color.DarkGray;
            this.panelIndicatorLight22.BackColor = Color.DarkGray;
            this.panelIndicatorLight23.BackColor = Color.DarkGray;
            this.panelIndicatorLight24.BackColor = Color.DarkGray;
            this.panelIndicatorLight25.BackColor = Color.DarkGray;
            this.panelIndicatorLight26.BackColor = Color.DarkGray;
            this.panelIndicatorLight27.BackColor = Color.DarkGray;
            this.panelIndicatorLight28.BackColor = Color.DarkGray;
            this.panelIndicatorLight29.BackColor = Color.DarkGray;
            this.panelIndicatorLight30.BackColor = Color.DarkGray;
            this.panelIndicatorLight31.BackColor = Color.DarkGray;
            this.panelIndicatorLight32.BackColor = Color.DarkGray;
        }

        private void btnMultiChlExe_Click(object sender, EventArgs e)
        {
            tabControl1.SelectedTab = tabPage1;
            tabControlSerialPort.SelectedTab = tabPageTransfers;

            if (!CheckSerialPortStatus())
            {
                return;
            }

            CommandsBase.ClearTransducersStatus();

            ListViewTransducerInfoClr(listView1);

            CloseAllPanelsIndicatorLight();

            TraversalHART0(sender);
        }

        private void UpdateIndicator(object[] args)
        {
            Panel indcator = (Panel)args[0];

            indcator.BackColor = Color.IndianRed;
        }

        private async void TraversalHART0(object sender)
        {
            bool bFlg = true;

            if (CommandsBase.bHasCMDExecuting == true)
            {
                SerialPortsBase.PrintMessage("有命令正在执行，请稍等！");
                return;
            }

            CommandsBase.bHasCMDExecuting = true;

            List<(CMDsGroup, TimeSpan)> CMDsGroups = new List<(CMDsGroup, TimeSpan)>();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl11");
            HART0ReadUniqueIdentifier hHARTCMD0 = new HART0ReadUniqueIdentifier(hARTSerialPort_woyatechModem, "Groups HART#0");
            HART14ReadPVTransducerInfo hHARTCMD14 = new HART14ReadPVTransducerInfo(hARTSerialPort_woyatechModem, "Groups HART#14");
            HART15ReadDeviceInfo hHARTCMD15 = new HART15ReadDeviceInfo(hARTSerialPort_woyatechModem, "Groups HART#15");

            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #0 All"], new ListViewUpdater(this.listView1));
            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #14 Upper"], new ListViewUpdater(this.listView1));
            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #14 Lower"], new ListViewUpdater(this.listView1));
            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #15 PV Upper"], new ListViewUpdater(this.listView1));
            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #15 PV Lower"], new ListViewUpdater(this.listView1));

            TextBox[] txtBoxAry = new TextBox[32]
            {
                this.txtBoxTransLongAddr1, this.txtBoxTransLongAddr2, this.txtBoxTransLongAddr3, this.txtBoxTransLongAddr4, this.txtBoxTransLongAddr5,
                this.txtBoxTransLongAddr6, this.txtBoxTransLongAddr7, this.txtBoxTransLongAddr8, this.txtBoxTransLongAddr9, this.txtBoxTransLongAddr10,
                this.txtBoxTransLongAddr11, this.txtBoxTransLongAddr12, this.txtBoxTransLongAddr13, this.txtBoxTransLongAddr14, this.txtBoxTransLongAddr15,
                this.txtBoxTransLongAddr16, this.txtBoxTransLongAddr17, this.txtBoxTransLongAddr18, this.txtBoxTransLongAddr19, this.txtBoxTransLongAddr20,
                this.txtBoxTransLongAddr21, this.txtBoxTransLongAddr22, this.txtBoxTransLongAddr23, this.txtBoxTransLongAddr24, this.txtBoxTransLongAddr25,
                this.txtBoxTransLongAddr26, this.txtBoxTransLongAddr27, this.txtBoxTransLongAddr28, this.txtBoxTransLongAddr29, this.txtBoxTransLongAddr30,
                this.txtBoxTransLongAddr31, this.txtBoxTransLongAddr32
            };

            // RGB Alarm
            BatchCaliBoardCMDsSwitchRGB batchBoardSwitchRGB = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Switch R Flashing", RGBSel.eRGB_G_Flashing);

            for (int i = 0; i < 32; i++)
            {
                if (gCheckBoxDevsSelectedAry[i].Checked)
                {
                    hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info[$"HART #0 chl{i + 1} LongAddress"], new TextBoxUpdater(txtBoxAry[i]));

                    if (bFlg)
                    {
                        gCMSsGroupsAry[i].AddCommands(
                            new List<(CommandsBase, TimeSpan)>()
                            {
                                (batchBoardSwitchRGB, TimeSpan.FromSeconds(1)),
                                (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (hHARTCMD0, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (hHARTCMD14, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (hHARTCMD15, TimeSpan.FromSeconds(0)),
                            }
                        );

                        bFlg = false;
                    }
                    else
                    {
                        gCMSsGroupsAry[i].AddCommands(
                            new List<(CommandsBase, TimeSpan)>()
                            {
                                (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (hHARTCMD0, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (hHARTCMD14, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (hHARTCMD15, TimeSpan.FromSeconds(0)),
                            }
                        );
                    }

                    // callbacks
                    object[] args = new object[]
                    {
                        gIndicatorAry[i],
                    };
                    CMDsGroupManager.AddGroupsCallback(i + 1, UpdateIndicator, args);

                    CMDsGroups.Add((gCMSsGroupsAry[i], TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
                }
            }

            CMDsGroupManager.AddGroupsEndCallback(RGBStatusUpdGroupsEndCallback, new object[0]);

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private async void RGBStatusUpdGroupsEndCallback(object[] args)
        {
            BatchCaliBoardCMDsSwitchRGB batchBoardSwitchRGB = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Switch R Flashing", RGBSel.eRGB_G_ON);
            await batchBoardSwitchRGB.ExecuteCMD();
        }

        private async Task<bool> WriteUpAndDownLimitRange()
        {
            if (!CheckSerialPortStatus())
            {
                return false;
            }

            List<(CMDsGroup, TimeSpan)> CMDsGroups = new List<(CMDsGroup, TimeSpan)>();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl11");
            HART135CustomCommand customCMD = null;

            List<byte> data = new List<byte>();

            int transducerUpper;
            int transducerLower;

            string currentRange = cboxSensorRange.Text;

            if (currentRange == "-3kPa～3kPa")
            {
                transducerUpper = 3000;
                transducerLower = -3000;
            }
            else if (currentRange == "-6kPa～6kPa")
            {
                transducerUpper = 6000;
                transducerLower = -6000;
            }
            else if (currentRange == "-40kPa～40kPa")
            {
                transducerUpper = 40000;
                transducerLower = -40000;
            }
            else if (currentRange == "-100kPa～250kPa")
            {
                transducerUpper = 250000;
                transducerLower = -100000;
            }
            else if (currentRange == "-100kPa～1MPa")
            {
                transducerUpper = 1000000;
                transducerLower = -100000;
            }
            else if (currentRange == "-100kPa～3MPa")
            {
                transducerUpper = 3000000;
                transducerLower = -100000;
            }
            else if (currentRange == "-100kPa～10MPa")
            {
                transducerUpper = 10000000;
                transducerLower = -100000;
            }
            else if (currentRange == "-100kPa～40MPa")
            {
                transducerUpper = 40000000;
                transducerLower = -100000;
            }
            else
            {
                return false;
            }

            data.Add((byte)((transducerUpper >> 0) & 0xff));
            data.Add((byte)((transducerUpper >> 8) & 0xff));
            data.Add((byte)((transducerUpper >> 16) & 0xff));
            data.Add((byte)((transducerUpper >> 24) & 0xff));

            data.Add((byte)((transducerLower >> 0) & 0xff));
            data.Add((byte)((transducerLower >> 8) & 0xff));
            data.Add((byte)((transducerLower >> 16) & 0xff));
            data.Add((byte)((transducerLower >> 24) & 0xff));

            customCMD = new HART135CustomCommand(hARTSerialPort_woyatechModem, "HART#135#83", CustomCommandsBase.SETPRERANGE, data: data);

            for (int i = 0; i < 32; i++)
            {
                if (gCheckBoxDevsSelectedAry[i].Checked)
                {
                    gCMSsGroupsAry[i].AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                    CMDsGroups.Add((gCMSsGroupsAry[i], TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
                }
            }

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();

            return true;
        }

        private async Task<bool> WriteTemperaturePointsAndTemperatures()
        {
            if (!CheckSerialPortStatus())
            {
                return false;
            }

            List<(CMDsGroup, TimeSpan)> CMDsGroups = new List<(CMDsGroup, TimeSpan)>();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl11");
            HART135CustomCommand customCMD = null;

            List<byte> data = new List<byte>();

            string temperaturePointNum = cboxTemperaturePoints.Text;
            byte temperPoints = 0;
            float temperature = 0.0f;
            byte[] tempData = new byte[4];

            if (byte.TryParse(temperaturePointNum, out temperPoints))
            {
                data.Add(temperPoints);
            }
            else
            {
                SerialPortsBase.PrintMessage("温度点个数--格式转换失败！");
                return false;
            }

            // temperature 1
            if (float.TryParse(txtBoxConfigTemp1.Text, out temperature))
            {
                tempData = BitConverter.GetBytes(temperature);

                if (!BitConverter.IsLittleEndian)
                {
                    Array.Reverse(tempData);
                }

                data.AddRange(tempData);
            }
            else
            {
                SerialPortsBase.PrintMessage("温度点1，格式错误！");
                return false;
            }
            // temperature 2
            if (float.TryParse(txtBoxConfigTemp2.Text, out temperature))
            {
                tempData = BitConverter.GetBytes(temperature);

                if (!BitConverter.IsLittleEndian)
                {
                    Array.Reverse(tempData);
                }

                data.AddRange(tempData);
            }
            else
            {
                SerialPortsBase.PrintMessage("温度点2，格式错误！");
                return false;
            }
            // temperature 3
            if (float.TryParse(txtBoxConfigTemp3.Text, out temperature))
            {
                tempData = BitConverter.GetBytes(temperature);

                if (!BitConverter.IsLittleEndian)
                {
                    Array.Reverse(tempData);
                }

                data.AddRange(tempData);
            }
            else
            {
                SerialPortsBase.PrintMessage("温度点3，格式错误！");
                return false;
            }

            // temperature 4
            if ((temperaturePointNum == "4") || (temperaturePointNum == "5") || (temperaturePointNum == "6") ||
                (temperaturePointNum == "7") || (temperaturePointNum == "8"))
            {
                if (float.TryParse(txtBoxConfigTemp4.Text, out temperature))
                {
                    tempData = BitConverter.GetBytes(temperature);

                    if (!BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(tempData);
                    }

                    data.AddRange(tempData);
                }
                else
                {
                    SerialPortsBase.PrintMessage("温度点4，格式错误！");
                    return false;
                }
            }
            // temperature 5
            if ((temperaturePointNum == "5") || (temperaturePointNum == "6") || (temperaturePointNum == "7") ||
                (temperaturePointNum == "8"))
            {
                if (float.TryParse(txtBoxConfigTemp5.Text, out temperature))
                {
                    tempData = BitConverter.GetBytes(temperature);

                    if (!BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(tempData);
                    }

                    data.AddRange(tempData);
                }
                else
                {
                    SerialPortsBase.PrintMessage("温度点5，格式错误！");
                    return false;
                }
            }
            // temperature 6
            if ((temperaturePointNum == "6") || (temperaturePointNum == "7") || (temperaturePointNum == "8"))
            {
                if (float.TryParse(txtBoxConfigTemp6.Text, out temperature))
                {
                    tempData = BitConverter.GetBytes(temperature);

                    if (!BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(tempData);
                    }

                    data.AddRange(tempData);
                }
                else
                {
                    SerialPortsBase.PrintMessage("温度点6，格式错误！");
                    return false;
                }
            }
            // temperature 7
            if ((temperaturePointNum == "7") || (temperaturePointNum == "8"))
            {
                if (float.TryParse(txtBoxConfigTemp7.Text, out temperature))
                {
                    tempData = BitConverter.GetBytes(temperature);

                    if (!BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(tempData);
                    }

                    data.AddRange(tempData);
                }
                else
                {
                    SerialPortsBase.PrintMessage("温度点7，格式错误！");
                    return false;
                }
            }
            // temperature 8
            if (temperaturePointNum == "8")
            {
                if (float.TryParse(txtBoxConfigTemp8.Text, out temperature))
                {
                    tempData = BitConverter.GetBytes(temperature);

                    if (!BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(tempData);
                    }

                    data.AddRange(tempData);
                }
                else
                {
                    SerialPortsBase.PrintMessage("温度点8，格式错误！");
                    return false;
                }
            }

            customCMD = new HART135CustomCommand(hARTSerialPort_woyatechModem, "HART#135#85", CustomCommandsBase.SETTEMPNUM, data: data);

            for (int i = 0; i < 32; i++)
            {
                if (gCheckBoxDevsSelectedAry[i].Checked)
                {
                    gCMSsGroupsAry[i].AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                    CMDsGroups.Add((gCMSsGroupsAry[i], TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
                }
            }

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();

            return true;
        }

        private async void WriteSensorRageOrTemperaturePoint(string type)
        {
            if (!CheckSerialPortStatus())
            {
                return;
            }

            List<(CMDsGroup, TimeSpan)> CMDsGroups = new List<(CMDsGroup, TimeSpan)>();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl11");
            HART135CustomCommand customCMD = null;

            List<byte> data = new List<byte>();

            if (type == "设置温补点数和温度值") 
            {
                string temperaturePointNum = coboxTempPointNum.Text;
                byte temperPoints = 0;
                float temperature = 0.0f;

                byte[] tempData = new byte[4];

                if (byte.TryParse(temperaturePointNum, out temperPoints))
                {
                    data.Add(temperPoints);
                }
                else
                {
                    SerialPortsBase.PrintMessage("温度点个数--转换失败！");
                }

                // temperature 1
                if (float.TryParse(txtBoxTemperature1.Text, out temperature))
                {
                    tempData = BitConverter.GetBytes(temperature);

                    if (!BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(tempData);
                    }

                    data.AddRange(tempData);
                }
                else
                {
                    SerialPortsBase.PrintMessage("温度点1，格式错误！");
                    return;
                }
                // temperature 2
                if (float.TryParse(txtBoxTemperature2.Text, out temperature))
                { 
                    tempData = BitConverter.GetBytes(temperature);

                    if (!BitConverter.IsLittleEndian)
                    { 
                        Array.Reverse(tempData);
                    }

                    data.AddRange(tempData);
                }
                else
                {
                    SerialPortsBase.PrintMessage("温度点2，格式错误！");
                    return;
                }
                // temperature 3
                if (float.TryParse(txtBoxTemperature3.Text, out temperature))
                { 
                    tempData = BitConverter.GetBytes(temperature);

                    if (!BitConverter.IsLittleEndian)
                    { 
                        Array.Reverse(tempData);
                    }

                    data.AddRange(tempData);
                }
                else
                {
                    SerialPortsBase.PrintMessage("温度点3，格式错误！");
                    return;
                }

                // temperature 4
                if ((temperaturePointNum == "4") || (temperaturePointNum == "5") || (temperaturePointNum == "6") || 
                    (temperaturePointNum == "7") || (temperaturePointNum == "8"))
                {
                    if (float.TryParse(txtBoxTemperature4.Text, out temperature))
                    {
                        tempData = BitConverter.GetBytes(temperature);

                        if (!BitConverter.IsLittleEndian)
                        {
                            Array.Reverse(tempData);
                        }

                        data.AddRange(tempData);
                    }
                    else
                    {
                        SerialPortsBase.PrintMessage("温度点4，格式错误！");
                        return;
                    }
                }
                // temperature 5
                if ((temperaturePointNum == "5") || (temperaturePointNum == "6") || (temperaturePointNum == "7") ||
                    (temperaturePointNum == "8"))
                {
                    if (float.TryParse(txtBoxTemperature5.Text, out temperature))
                    {
                        tempData = BitConverter.GetBytes(temperature);

                        if (!BitConverter.IsLittleEndian)
                        {
                            Array.Reverse(tempData);
                        }

                        data.AddRange(tempData);
                    }
                    else
                    {
                        SerialPortsBase.PrintMessage("温度点5，格式错误！");
                        return;
                    }
                }
                // temperature 6
                if ((temperaturePointNum == "6") || (temperaturePointNum == "7") || (temperaturePointNum == "8"))
                {
                    if (float.TryParse(txtBoxTemperature6.Text, out temperature))
                    {
                        tempData = BitConverter.GetBytes(temperature);

                        if (!BitConverter.IsLittleEndian)
                        {
                            Array.Reverse(tempData);
                        }

                        data.AddRange(tempData);
                    }
                    else
                    {
                        SerialPortsBase.PrintMessage("温度点6，格式错误！");
                        return;
                    }
                }
                // temperature 7
                if ((temperaturePointNum == "7") || (temperaturePointNum == "8"))
                {
                    if (float.TryParse(txtBoxTemperature7.Text, out temperature))
                    {
                        tempData = BitConverter.GetBytes(temperature);

                        if (!BitConverter.IsLittleEndian)
                        {
                            Array.Reverse(tempData);
                        }

                        data.AddRange(tempData);
                    }
                    else
                    {
                        SerialPortsBase.PrintMessage("温度点7，格式错误！");
                        return;
                    }
                }
                // temperature 8
                if (temperaturePointNum == "8")
                {
                    if (float.TryParse(txtBoxTemperature8.Text, out temperature))
                    {
                        tempData = BitConverter.GetBytes(temperature);

                        if (!BitConverter.IsLittleEndian)
                        {
                            Array.Reverse(tempData);
                        }

                        data.AddRange(tempData);
                    }
                    else
                    {
                        SerialPortsBase.PrintMessage("温度点8，格式错误！");
                        return;
                    }
                }

                customCMD = new HART135CustomCommand(hARTSerialPort_woyatechModem, "HART#135#85", CustomCommandsBase.SETTEMPNUM, data: data);
            }
            else if (type == "设置传感器上下限")
            {
                int transducerUpper;
                int transducerLower;

                string currentRange = cboxConfigRange.Text;

                if (currentRange == "-3kPa～3kPa")
                {
                    transducerUpper = 3000;
                    transducerLower = -3000;
                }
                else if (currentRange == "-6kPa～6kPa")
                {
                    transducerUpper = 6000;
                    transducerLower = -6000;
                }
                else if (currentRange == "-40kPa～40kPa")
                {
                    transducerUpper = 40000;
                    transducerLower = -40000;
                }
                else if (currentRange == "-100kPa～250kPa")
                {
                    transducerUpper = 250000;
                    transducerLower = -100000;
                }
                else if (currentRange == "-100kPa～1MPa")
                {
                    transducerUpper = 1000000;
                    transducerLower = -100000;
                }
                else if (currentRange == "-100kPa～3MPa")
                {
                    transducerUpper = 3000000;
                    transducerLower = -100000;
                }
                else if (currentRange == "-100kPa～10MPa")
                {
                    transducerUpper = 10000000;
                    transducerLower = -100000;
                }
                else if (currentRange == "-100kPa～40MPa")
                {
                    transducerUpper = 40000000;
                    transducerLower = -100000;
                }
                else
                {
                    return;
                }

                data.Add((byte)((transducerUpper >> 0) & 0xff));
                data.Add((byte)((transducerUpper >> 8) & 0xff));
                data.Add((byte)((transducerUpper >> 16) & 0xff));
                data.Add((byte)((transducerUpper >> 24) & 0xff));

                data.Add((byte)((transducerLower >> 0) & 0xff));
                data.Add((byte)((transducerLower >> 8) & 0xff));
                data.Add((byte)((transducerLower >> 16) & 0xff));
                data.Add((byte)((transducerLower >> 24) & 0xff));

                customCMD = new HART135CustomCommand(hARTSerialPort_woyatechModem, "HART#135#83", CustomCommandsBase.SETPRERANGE, data:data);
            }

            if (this.chkBoxTransfer1.Checked)
            {
                CMDsGroup1.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup1, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer2.Checked)
            {
                CMDsGroup2.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup2, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer3.Checked)
            {
                CMDsGroup3.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup3, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer4.Checked)
            {
                CMDsGroup4.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup4, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer5.Checked)
            {
                CMDsGroup5.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup5, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer6.Checked)
            {
                CMDsGroup6.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup6, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer7.Checked)
            {
                CMDsGroup7.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup7, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer8.Checked)
            {
                CMDsGroup8.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup8, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer9.Checked)
            {
                CMDsGroup9.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup9, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer10.Checked)
            {
                CMDsGroup10.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup10, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer11.Checked)
            {
                CMDsGroup11.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup11, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer12.Checked)
            {
                CMDsGroup12.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup12, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer13.Checked)
            {
                CMDsGroup13.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup13, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer14.Checked)
            {
                CMDsGroup14.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup14, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer15.Checked)
            {
                CMDsGroup15.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup15, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer16.Checked)
            {
                CMDsGroup16.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup16, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer17.Checked)
            {
                CMDsGroup17.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup17, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer18.Checked)
            {
                CMDsGroup18.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup18, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer19.Checked)
            {
                CMDsGroup19.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup19, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer20.Checked)
            {
                CMDsGroup20.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup20, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer21.Checked)
            {
                CMDsGroup21.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup21, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer22.Checked)
            {
                CMDsGroup22.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup22, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer23.Checked)
            {
                CMDsGroup23.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup23, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer24.Checked)
            {
                CMDsGroup24.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup24, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer25.Checked)
            {
                CMDsGroup25.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup25, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer26.Checked)
            {
                CMDsGroup26.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup26, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer27.Checked)
            {
                CMDsGroup27.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup27, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer28.Checked)
            {
                CMDsGroup28.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup28, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer29.Checked)
            {
                CMDsGroup29.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup29, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer30.Checked)
            {
                CMDsGroup30.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup30, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer31.Checked)
            {
                CMDsGroup31.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup31, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (this.chkBoxTransfer32.Checked)
            {
                CMDsGroup32.AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                CMDsGroups.Add((CMDsGroup32, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private void listView2_Resize(object sender, EventArgs e)
        {
            AdjustListViewColumnWidthFitInfo();
        }

        //private void btnLoadData_Click(object sender, EventArgs e)
        //{
        //    FolderBrowserDialog dialog = new FolderBrowserDialog();
        //    string assemblyPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
        //    string currentDir = Path.GetDirectoryName(assemblyPath);
        //    string parentDir = Path.GetDirectoryName(currentDir);

        //    dialog.Description = "请选择包含所有采集数据的文件夹";
        //    dialog.SelectedPath = parentDir;

        //    if (dialog.ShowDialog() == DialogResult.OK)
        //    {
        //        string selectedPath = dialog.SelectedPath;

        //        _jsonFolderPath = selectedPath;

        //        LoadJsonFilesToTreeView(selectedPath);

        //        // Load *_Config.json
        //        LoadConfigDataAndUpdGUI(selectedPath);
        //    }
        //}

        private void LoadConfigDataAndUpdGUI(string folderPath)
        {
            string[] configFile = Directory.GetFiles(folderPath, "*_Config.json", SearchOption.TopDirectoryOnly);

            string jsonFileString = File.ReadAllText(configFile[0]);

            JsonConfigInfo.configInfo = JsonConvert.DeserializeObject<ConfigInfo>(jsonFileString);

            try
            {
                txtBoxConfigSN.Text = JsonConfigInfo.configInfo.OrderSerialNumber;
                numericConfigRangeUp.Value = JsonConfigInfo.configInfo.RangeUp;
                numericConfigRangeDown.Value = JsonConfigInfo.configInfo.RangeDown;

                int index = cboxPressurePoints.FindString((JsonConfigInfo.configInfo.EqualVal + 1).ToString());
                if (index != -1)
                {
                    cboxPressurePoints.SelectedIndex = index;
                }
                else
                {
                    _bConfigInfoIsOK = false;
                    MessageBox.Show("参数\"压力点数\"不在配置选项内!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                    return;
                }

                index = cboxTemperaturePoints.FindString((JsonConfigInfo.configInfo.TemperaturePoints).ToString());
                if (index != -1)
                {
                    cboxTemperaturePoints.SelectedIndex = index;
                }
                else
                {
                    _bConfigInfoIsOK = false;
                    MessageBox.Show("参数\"温度点数\"不在配置选项内!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                    return;
                }

                txtBoxConfigTemp1.Text = JsonConfigInfo.configInfo.Temperature1.Trim('℃');
                txtBoxConfigTemp2.Text = JsonConfigInfo.configInfo.Temperature2.Trim('℃');
                txtBoxConfigTemp3.Text = JsonConfigInfo.configInfo.Temperature3.Trim('℃');
                txtBoxConfigTemp4.Text = JsonConfigInfo.configInfo.Temperature4.Trim('℃');
                txtBoxConfigTemp5.Text = JsonConfigInfo.configInfo.Temperature5.Trim('℃');
                txtBoxConfigTemp6.Text = JsonConfigInfo.configInfo.Temperature6.Trim('℃');

                txtBoxFluctuationThreshold.Text = (JsonConfigInfo.configInfo.PressureFluctuationThreshold).ToString();
                txtBoxLinearityErrorThreshold.Text = (JsonConfigInfo.configInfo.PressureLinearityErrThreshold).ToString();

                index = cboxPreFitDegree.FindString((JsonConfigInfo.configInfo.PressureFitDegree).ToString());
                if (index != -1)
                {
                    cboxPreFitDegree.SelectedIndex = index;
                }
                else
                {
                    _bConfigInfoIsOK = false;
                    MessageBox.Show("参数\"压力拟合阶数\"不在配置选项内!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                    return;
                }

                index = cboxTempFitDegree.FindString((JsonConfigInfo.configInfo.TemperatureFitDegree).ToString());
                if (index != -1)
                {
                    cboxTempFitDegree.SelectedIndex = index;
                }
                else
                {
                    _bConfigInfoIsOK = false;
                    MessageBox.Show("参数\"温度拟合阶数\"不在配置选项内!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                    return;
                }

                UpdateTransferLongAddrAndSN();
                UpdateConfigInfoToContols();
                UpdateSrcDataAndFitTargetDataGUI(folderPath, true);

                _bConfigInfoIsOK = true;
            }
            catch (Exception ex)
            {
                _bConfigInfoIsOK = false;
                MessageBox.Show("加载配置信息错误: " + ex.Message, "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
        }

        private void LoadJsonFilesToTreeView(string folderPath)
        {
            treeViewLoadData.Nodes.Clear();

            TreeNode rootNode = new TreeNode(Path.GetFileName(folderPath));
            treeViewLoadData.Nodes.Add(rootNode);

            AddDirectoryNodes(folderPath, rootNode);

            treeViewLoadData.ExpandAll();
            treeViewLoadData.Nodes[0].EnsureVisible();
        }

        private void AddDirectoryNodes(string directoryPath, TreeNode parentNode)
        {
            try
            {
                // 添加子文件夹节点
                string[] subDirectories = Directory.GetDirectories(directoryPath);

                foreach (string subDirectory in subDirectories)
                {
                    TreeNode subDirNode = new TreeNode(Path.GetFileName(subDirectory));
                    parentNode.Nodes.Add(subDirNode);

                    // 递归添加子文件夹及其中的 JSON 文件
                    AddDirectoryNodes(subDirectory, subDirNode);
                }

                // 添加 JSON 文件节点
                string[] jsonFiles = Directory.GetFiles(directoryPath, "*.json");

                foreach (string jsonFile in jsonFiles)
                {
                    TreeNode jsonNode = new TreeNode(Path.GetFileName(jsonFile));
                    parentNode.Nodes.Add(jsonNode);
                }
            }
            catch (UnauthorizedAccessException)
            {
                MessageBox.Show("无法访问文件夹: " + directoryPath, "权限错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (Exception ex)
            {
                MessageBox.Show("错误: " + ex.Message, "未知错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void treeViewLoadData_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            string selectedFileName = e.Node.Text;

            string fullFilePath = null;

            string searchDataFilePattern = @"^.*\[-?\d+℃\]-\[-?\d+(\.\d+)?kPa\].json$";

            try
            {
                if (Regex.IsMatch(selectedFileName, searchDataFilePattern))
                {
                    fullFilePath = Path.Combine(_exePath, "result", JsonConfigInfo.configInfo.OrderSerialNumber, e.Node.Parent.Text, e.Node.Text);

                    string jsonFileString = File.ReadAllText(fullFilePath);
                    JsonDevsInfo info = JsonConvert.DeserializeObject<JsonDevsInfo>(jsonFileString);

                    ListViewTransducerInfoClr(listViewSrcData);

                    for (byte i = 0; i < 32; i++)
                    {
                        int itemID = (int)(i * 10);

                        if (JsonConfigInfo.configInfo.transducersInfo[i].Status)
                        {
                            listViewSrcData.Items[0 + itemID].SubItems[1].Text = info.dataInfo[i].Data["压力(上行)"][0];
                            listViewSrcData.Items[1 + itemID].SubItems[1].Text = info.dataInfo[i].Data["压力(上行)"][1];
                            listViewSrcData.Items[2 + itemID].SubItems[1].Text = info.dataInfo[i].Data["压力(上行)"][2];
                            listViewSrcData.Items[3 + itemID].SubItems[1].Text = info.dataInfo[i].Data["压力(上行)"][3];
                            listViewSrcData.Items[4 + itemID].SubItems[1].Text = info.dataInfo[i].Data["压力(上行)"][4];
                            listViewSrcData.Items[5 + itemID].SubItems[1].Text = info.dataInfo[i].Data["压力(上行)"][5];
                            listViewSrcData.Items[6 + itemID].SubItems[1].Text = info.dataInfo[i].Data["压力(上行)"][6];
                            listViewSrcData.Items[7 + itemID].SubItems[1].Text = info.dataInfo[i].Data["压力(上行)"][7];
                            listViewSrcData.Items[8 + itemID].SubItems[1].Text = info.dataInfo[i].Data["压力(上行)"][8];
                            listViewSrcData.Items[9 + itemID].SubItems[1].Text = info.dataInfo[i].Data["压力(上行)"][9];

                            listViewSrcData.Items[0 + itemID].SubItems[2].Text = info.dataInfo[i].Data["温度(上行)"][0];
                            listViewSrcData.Items[1 + itemID].SubItems[2].Text = info.dataInfo[i].Data["温度(上行)"][1];
                            listViewSrcData.Items[2 + itemID].SubItems[2].Text = info.dataInfo[i].Data["温度(上行)"][2];
                            listViewSrcData.Items[3 + itemID].SubItems[2].Text = info.dataInfo[i].Data["温度(上行)"][3];
                            listViewSrcData.Items[4 + itemID].SubItems[2].Text = info.dataInfo[i].Data["温度(上行)"][4];
                            listViewSrcData.Items[5 + itemID].SubItems[2].Text = info.dataInfo[i].Data["温度(上行)"][5];
                            listViewSrcData.Items[6 + itemID].SubItems[2].Text = info.dataInfo[i].Data["温度(上行)"][6];
                            listViewSrcData.Items[7 + itemID].SubItems[2].Text = info.dataInfo[i].Data["温度(上行)"][7];
                            listViewSrcData.Items[8 + itemID].SubItems[2].Text = info.dataInfo[i].Data["温度(上行)"][8];
                            listViewSrcData.Items[9 + itemID].SubItems[2].Text = info.dataInfo[i].Data["温度(上行)"][9];

                            listViewSrcData.Items[0 + itemID].SubItems[3].Text = info.dataInfo[i].Data["压力(下行)"][0];
                            listViewSrcData.Items[1 + itemID].SubItems[3].Text = info.dataInfo[i].Data["压力(下行)"][1];
                            listViewSrcData.Items[2 + itemID].SubItems[3].Text = info.dataInfo[i].Data["压力(下行)"][2];
                            listViewSrcData.Items[3 + itemID].SubItems[3].Text = info.dataInfo[i].Data["压力(下行)"][3];
                            listViewSrcData.Items[4 + itemID].SubItems[3].Text = info.dataInfo[i].Data["压力(下行)"][4];
                            listViewSrcData.Items[5 + itemID].SubItems[3].Text = info.dataInfo[i].Data["压力(下行)"][5];
                            listViewSrcData.Items[6 + itemID].SubItems[3].Text = info.dataInfo[i].Data["压力(下行)"][6];
                            listViewSrcData.Items[7 + itemID].SubItems[3].Text = info.dataInfo[i].Data["压力(下行)"][7];
                            listViewSrcData.Items[8 + itemID].SubItems[3].Text = info.dataInfo[i].Data["压力(下行)"][8];
                            listViewSrcData.Items[9 + itemID].SubItems[3].Text = info.dataInfo[i].Data["压力(下行)"][9];

                            listViewSrcData.Items[0 + itemID].SubItems[4].Text = info.dataInfo[i].Data["温度(下行)"][0];
                            listViewSrcData.Items[1 + itemID].SubItems[4].Text = info.dataInfo[i].Data["温度(下行)"][1];
                            listViewSrcData.Items[2 + itemID].SubItems[4].Text = info.dataInfo[i].Data["温度(下行)"][2];
                            listViewSrcData.Items[3 + itemID].SubItems[4].Text = info.dataInfo[i].Data["温度(下行)"][3];
                            listViewSrcData.Items[4 + itemID].SubItems[4].Text = info.dataInfo[i].Data["温度(下行)"][4];
                            listViewSrcData.Items[5 + itemID].SubItems[4].Text = info.dataInfo[i].Data["温度(下行)"][5];
                            listViewSrcData.Items[6 + itemID].SubItems[4].Text = info.dataInfo[i].Data["温度(下行)"][6];
                            listViewSrcData.Items[7 + itemID].SubItems[4].Text = info.dataInfo[i].Data["温度(下行)"][7];
                            listViewSrcData.Items[8 + itemID].SubItems[4].Text = info.dataInfo[i].Data["温度(下行)"][8];
                            listViewSrcData.Items[9 + itemID].SubItems[4].Text = info.dataInfo[i].Data["温度(下行)"][9];
                        }
                    }
                }
                else if(selectedFileName.Contains("Config.json"))
                {
                    fullFilePath = Path.Combine(_exePath, "result", JsonConfigInfo.configInfo.OrderSerialNumber, e.Node.Text);

                    JsonConfigInfo.configInfo = JsonConfigInfo.JsonLoadInfo(fullFilePath);

                    SerialPortsBase.PrintMessageNoTime("\r\n***********************配置参数***********************");
                    SerialPortsBase.PrintMessageNoTime($"订单序列号(OrderSerialNumber): {JsonConfigInfo.configInfo.OrderSerialNumber}");
                    SerialPortsBase.PrintMessageNoTime($"传感器量程(SensorRange): {JsonConfigInfo.configInfo.RangeUp}");
                    SerialPortsBase.PrintMessageNoTime($"量程上限(RangeUp): {JsonConfigInfo.configInfo.RangeUp}");
                    SerialPortsBase.PrintMessageNoTime($"量程下限(RangeDown): {JsonConfigInfo.configInfo.RangeDown}");
                    SerialPortsBase.PrintMessageNoTime($"压力等分点数(EqualVal): {JsonConfigInfo.configInfo.EqualVal}");
                    SerialPortsBase.PrintMessageNoTime($"温度点数(EqualVal): {JsonConfigInfo.configInfo.TemperaturePoints}");
                    SerialPortsBase.PrintMessageNoTime($"温度点1(Temperature1): {JsonConfigInfo.configInfo.Temperature1}");
                    SerialPortsBase.PrintMessageNoTime($"温度点2(Temperature2): {JsonConfigInfo.configInfo.Temperature2}");
                    SerialPortsBase.PrintMessageNoTime($"温度点3(Temperature3): {JsonConfigInfo.configInfo.Temperature3}");
                    SerialPortsBase.PrintMessageNoTime($"温度点4(Temperature4): {JsonConfigInfo.configInfo.Temperature4}");
                    SerialPortsBase.PrintMessageNoTime($"温度点5(Temperature5): {JsonConfigInfo.configInfo.Temperature5}");
                    SerialPortsBase.PrintMessageNoTime($"温度点6(Temperature6): {JsonConfigInfo.configInfo.Temperature6}");
                    SerialPortsBase.PrintMessageNoTime($"温度点7(Temperature7): {JsonConfigInfo.configInfo.Temperature7}");
                    SerialPortsBase.PrintMessageNoTime($"温度点8(Temperature8): {JsonConfigInfo.configInfo.Temperature8}");
                    SerialPortsBase.PrintMessageNoTime("***********************配置参数***********************\r\n");

                }

                SerialPortsBase.PrintMessage(fullFilePath);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"读取 JSON 文件{fullFilePath}出错：" + ex.Message);
            }
        }

        private List<string> GetAllJsonFiles(string folderPath)
        {
            List<string> jsonFiles = new List<string>();

            try
            {
                jsonFiles.AddRange(Directory.GetFiles(folderPath, "*.json"));

                foreach (var subDirectory in Directory.GetDirectories(folderPath))
                {
                    jsonFiles.AddRange(GetAllJsonFiles(subDirectory));
                }
            }
            catch (UnauthorizedAccessException ex)
            {
                MessageBox.Show("权限错误: " + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (Exception ex)
            {
                MessageBox.Show("未知错误: " + ex.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            return jsonFiles;
        }

        private bool bCheckTransducersLongAddrAndSN()
        {
            TextBox[] txtBoxTransLongAddrsCtls = new TextBox[32]
            {
                txtBoxTransLongAddr1, txtBoxTransLongAddr2, txtBoxTransLongAddr3, txtBoxTransLongAddr4,
                txtBoxTransLongAddr5, txtBoxTransLongAddr6, txtBoxTransLongAddr7, txtBoxTransLongAddr8,
                txtBoxTransLongAddr9, txtBoxTransLongAddr10, txtBoxTransLongAddr11, txtBoxTransLongAddr12,
                txtBoxTransLongAddr13, txtBoxTransLongAddr14, txtBoxTransLongAddr15, txtBoxTransLongAddr16,
                txtBoxTransLongAddr17, txtBoxTransLongAddr18, txtBoxTransLongAddr19, txtBoxTransLongAddr20,
                txtBoxTransLongAddr21, txtBoxTransLongAddr22, txtBoxTransLongAddr23, txtBoxTransLongAddr24,
                txtBoxTransLongAddr25, txtBoxTransLongAddr26, txtBoxTransLongAddr27, txtBoxTransLongAddr28,
                txtBoxTransLongAddr29, txtBoxTransLongAddr30, txtBoxTransLongAddr31, txtBoxTransLongAddr32,
            };

            TextBox[] txtBoxTransLongSNCtls = new TextBox[32]
            {
                txtBoxTransSN1, txtBoxTransSN2, txtBoxTransSN3, txtBoxTransSN4, txtBoxTransSN5,
                txtBoxTransSN6, txtBoxTransSN7, txtBoxTransSN8, txtBoxTransSN9, txtBoxTransSN10, 
                txtBoxTransSN11, txtBoxTransSN12, txtBoxTransSN13, txtBoxTransSN14, txtBoxTransSN15,
                txtBoxTransSN16, txtBoxTransSN17, txtBoxTransSN18, txtBoxTransSN19, txtBoxTransSN20,
                txtBoxTransSN21, txtBoxTransSN22, txtBoxTransSN23, txtBoxTransSN24, txtBoxTransSN25,
                txtBoxTransSN26, txtBoxTransSN27, txtBoxTransSN28, txtBoxTransSN29, txtBoxTransSN30,
                txtBoxTransSN31, txtBoxTransSN32,
            };

            for (int i = 0; i < 32; i++)
            {
                if (gCheckBoxDevsSelectedAry[i].Checked)
                {
                    if (string.IsNullOrEmpty(txtBoxTransLongAddrsCtls[i].Text))
                    {
                        MessageBox.Show($"变送器{i + 1} \"长地址\"不能为空!");
                        return false;
                    }

                    if (string.IsNullOrEmpty(txtBoxTransLongSNCtls[i].Text))
                    {
                        MessageBox.Show($"变送器{i + 1} \"编号\"不能为空!");
                        return false;
                    }
                }    
            }

            return true;
        }

        private async void btnSaveConfigInfo_Click(object sender, EventArgs e)
        {
            CloseAllPanelsIndicatorLight();

            if (!isTransducersSelected())
            {
                _bConfigInfoIsOK = false;
                return;
            }

            if (!bCheckTransducersLongAddrAndSN())
            {
                _bConfigInfoIsOK = false;
                return;
            }

            if (string.IsNullOrEmpty(txtBoxConfigSN.Text))
            {
                _bConfigInfoIsOK = false;
                MessageBox.Show("请输入\"订单编号\"!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                return;
            }
            else
            {
                JsonConfigInfo.configInfo.OrderSerialNumber = txtBoxConfigSN.Text;
            }

            JsonConfigInfo.configInfo.SensorRange = cboxSensorRange.Text;

            if (string.IsNullOrEmpty(cboxPressurePoints.Text))
            {
                _bConfigInfoIsOK = false;
                MessageBox.Show("请选择\"压力点数\"!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                return;
            }
            else
            {
                byte equalPoints;
                if (byte.TryParse(cboxPressurePoints.Text, out equalPoints))
                {
                    JsonConfigInfo.configInfo.EqualVal = (byte)(equalPoints - 1);
                }
                else
                {
                    _bConfigInfoIsOK = false;
                    MessageBox.Show("\"压力点数\"格式错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                    return;
                }
            }

            if (string.IsNullOrEmpty(cboxTemperaturePoints.Text))
            {
                _bConfigInfoIsOK = false;
                MessageBox.Show("请输入\"温度点数\"!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                return;
            }
            else
            {
                byte temperaturePoints;
                if (byte.TryParse(cboxTemperaturePoints.Text, out temperaturePoints))
                {
                    JsonConfigInfo.configInfo.TemperaturePoints = temperaturePoints;
                }
                else
                {
                    _bConfigInfoIsOK = false;
                    MessageBox.Show("\"温度点数\"格式错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                    return;
                }
            }

            int temperature = 0;
            if (int.TryParse(txtBoxConfigTemp1.Text, out temperature))
            {
                JsonConfigInfo.configInfo.Temperature1 = txtBoxConfigTemp1.Text + "℃";
            }
            else
            {
                _bConfigInfoIsOK = false;
                MessageBox.Show("\"温度1(℃)\"格式错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                return;
            }

            if (int.TryParse(txtBoxConfigTemp2.Text, out temperature))
            {
                JsonConfigInfo.configInfo.Temperature2 = txtBoxConfigTemp2.Text + "℃";
            }
            else
            {
                _bConfigInfoIsOK = false;
                MessageBox.Show("\"温度2(℃)\"格式错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                return;
            }

            if (int.TryParse(txtBoxConfigTemp3.Text, out temperature))
            {
                JsonConfigInfo.configInfo.Temperature3 = txtBoxConfigTemp3.Text + "℃";
            }
            else
            {
                _bConfigInfoIsOK = false;
                MessageBox.Show("\"温度3(℃)\"格式错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                return;
            }

            if (cboxTemperaturePoints.Text == "6")
            {
                if (int.TryParse(txtBoxConfigTemp4.Text, out temperature))
                {
                    JsonConfigInfo.configInfo.Temperature4 = txtBoxConfigTemp4.Text + "℃";
                }
                else
                {
                    _bConfigInfoIsOK = false;
                    MessageBox.Show("\"温度4(℃)\"格式错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                    return;
                }

                if (int.TryParse(txtBoxConfigTemp5.Text, out temperature))
                {
                    JsonConfigInfo.configInfo.Temperature5 = txtBoxConfigTemp5.Text + "℃";
                }
                else
                {
                    _bConfigInfoIsOK = false;
                    MessageBox.Show("\"温度5(℃)\"格式错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                    return;
                }

                if (int.TryParse(txtBoxConfigTemp6.Text, out temperature))
                {
                    JsonConfigInfo.configInfo.Temperature6 = txtBoxConfigTemp6.Text + "℃";
                }
                else
                {
                    _bConfigInfoIsOK = false;
                    MessageBox.Show("\"温度6(℃)\"格式错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                    return;
                }
            }

            double fluctuationThreshold;
            if (double.TryParse(txtBoxFluctuationThreshold.Text, out fluctuationThreshold))
            {
                JsonConfigInfo.configInfo.PressureFluctuationThreshold = fluctuationThreshold;
            }
            else
            {
                _bConfigInfoIsOK = false;
                MessageBox.Show("\"压力波动阈值(%)\"格式错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                return;
            }

            if (double.TryParse(txtBoxLinearityErrorThreshold.Text, out fluctuationThreshold))
            {
                JsonConfigInfo.configInfo.PressureLinearityErrThreshold = fluctuationThreshold;
            }
            else
            {
                _bConfigInfoIsOK = false;
                MessageBox.Show("\"压力线性度阈值(%)\"格式错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                return;
            }

            byte fitDegree;
            if (byte.TryParse(cboxPreFitDegree.Text, out fitDegree))
            {
                JsonConfigInfo.configInfo.PressureFitDegree = fitDegree;
            }
            else
            {
                _bConfigInfoIsOK = false;
                MessageBox.Show("\"压力拟合阶数\"格式错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                return;
            }

            if (byte.TryParse(cboxTempFitDegree.Text, out fitDegree))
            {
                JsonConfigInfo.configInfo.TemperatureFitDegree = fitDegree;
            }
            else
            {
                _bConfigInfoIsOK = false;
                MessageBox.Show("\"温度拟合阶数\"格式错误!", "错误", buttons:MessageBoxButtons.OK, icon:MessageBoxIcon.Error);
                return;
            }

            JsonConfigInfo.configInfo.RangeUp = (int)numericConfigRangeUp.Value;
            JsonConfigInfo.configInfo.RangeDown = (int)numericConfigRangeDown.Value;

            try
            {
                UpdateConfigInfo();

                UpdExcelTitle();

                string fileName = $"{JsonConfigInfo.configInfo.OrderSerialNumber}_Config.json";

                // 构造“温补数据”文件夹的完整路径
                string fileDirPath = Path.Combine(_exePath, "result", txtBoxConfigSN.Text);

                // 检查文件夹是否存在，如果不存在则创建它
                if (!Directory.Exists(fileDirPath))
                {
                    Directory.CreateDirectory(fileDirPath);
                }
                else
                {
                    var result = MessageBox.Show("文件已存在，是否覆盖？", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

                    if (result == DialogResult.No)
                    {
                        return;
                    }
                }

                // 构造完整的文件路径
                string filePath = Path.Combine(fileDirPath, fileName);

                var settings = new JsonSerializerSettings
                {
                    Formatting = Formatting.Indented,
                    NullValueHandling = NullValueHandling.Include,
                };

                var jsonString = JsonConvert.SerializeObject(JsonConfigInfo.configInfo, settings);

                File.WriteAllText(filePath, jsonString);

                UpdateConfigInfoToContols();
                //UpdateFitTargetDataControl();

                string jsonFilePath = Path.Combine(_exePath, "result", JsonConfigInfo.configInfo.OrderSerialNumber);
                // update treeViewLoadData
                LoadJsonFilesToTreeView(jsonFilePath);
                // update data fit listViewFitData
                UpdateSrcDataAndFitTargetDataGUI(jsonFilePath, true);

                RetestUpdDataToUI();

                _bConfigInfoIsOK = true;

                SerialPortsBase.PrintMessage($"{filePath}文件保存成功！");

                var res = MessageBox.Show("是否设置量程和温度点参数？", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

                if (res == DialogResult.No)
                {
                    return;
                }

                // Write Range
                if (await WriteUpAndDownLimitRange())
                {
                    SerialPortsBase.PrintMessage("传感器量程设置成功！\r\n");
                }
                else
                {
                    MessageBox.Show("传感器量程设置失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                    return;
                }

                // Write Temperature points and temperatures
                if (await WriteTemperaturePointsAndTemperatures())
                {
                    SerialPortsBase.PrintMessage("温度点和温度设置成功！\r\n");
                }
                else
                {
                    MessageBox.Show("温度点和温度设置失败!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                    return;
                }

                //if (JsonConfigInfo.JsonFileSaveInfo(fileName))
                //{
                //    SerialPortsBase.PrintMessage($"{fileName}文件保存成功！\r\n");

                //    UpdateConfigInfoToContols();
                //    UpdateFitTargetDataControl();

                //    // Write Range
                //    if (await WriteUpAndDownLimitRange())
                //    {
                //        SerialPortsBase.PrintMessage("传感器量程设置成功！\r\n");
                //    }
                //    else
                //    {
                //        MessageBox.Show("传感器量程设置失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                //        return;
                //    }

                //    // Write Temperature points and temperatures
                //    if (await WriteTemperaturePointsAndTemperatures())
                //    {
                //        SerialPortsBase.PrintMessage("温度点和温度设置成功！\r\n");
                //    }
                //    else
                //    {
                //        MessageBox.Show("温度点和温度设置失败!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                //        return;
                //    }

                //    _bConfigInfoIsOK = true;
                //}
            }
            catch (Exception ex)
            {
                _bConfigInfoIsOK = false;
                MessageBox.Show(ex.Message, "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
        }

        private void btnLoadConfigInfo_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.InitialDirectory = Path.Combine(_exePath, "result");
            openFileDialog.Filter = "JSON Files (*.json)|*.json";

            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                string filePath = openFileDialog.FileName;

                string jsonString = File.ReadAllText(filePath);
                JsonConfigInfo.configInfo = JsonConvert.DeserializeObject<ConfigInfo>(jsonString);

                try
                {
                    txtBoxConfigSN.Text = JsonConfigInfo.configInfo.OrderSerialNumber;

                    int index = cboxSensorRange.FindString(JsonConfigInfo.configInfo.SensorRange);
                    cboxSensorRange.SelectedIndex = index >= 0 ? index : 0;

                    numericConfigRangeUp.Value = JsonConfigInfo.configInfo.RangeUp;
                    numericConfigRangeDown.Value = JsonConfigInfo.configInfo.RangeDown;

                    index = cboxPressurePoints.FindString((JsonConfigInfo.configInfo.EqualVal + 1).ToString());
                    if (index != -1)
                    {
                        cboxPressurePoints.SelectedIndex = index;
                    }
                    else
                    {
                        _bConfigInfoIsOK = false;
                        MessageBox.Show("参数\"压力点数\"不在配置选项内!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                        return;
                    }

                    index = cboxTemperaturePoints.FindString((JsonConfigInfo.configInfo.TemperaturePoints).ToString());
                    if (index != -1)
                    {
                        cboxTemperaturePoints.SelectedIndex = index;
                    }
                    else
                    {
                        _bConfigInfoIsOK = false;
                        MessageBox.Show("参数\"温度点数\"不在配置选项内!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                        return;
                    }

                    txtBoxConfigTemp1.Text = JsonConfigInfo.configInfo.Temperature1.Trim('℃');
                    txtBoxConfigTemp2.Text = JsonConfigInfo.configInfo.Temperature2.Trim('℃');
                    txtBoxConfigTemp3.Text = JsonConfigInfo.configInfo.Temperature3.Trim('℃');
                    txtBoxConfigTemp4.Text = JsonConfigInfo.configInfo.Temperature4.Trim('℃');
                    txtBoxConfigTemp5.Text = JsonConfigInfo.configInfo.Temperature5.Trim('℃');
                    txtBoxConfigTemp6.Text = JsonConfigInfo.configInfo.Temperature6.Trim('℃');

                    txtBoxFluctuationThreshold.Text = (JsonConfigInfo.configInfo.PressureFluctuationThreshold).ToString();
                    txtBoxLinearityErrorThreshold.Text = (JsonConfigInfo.configInfo.PressureLinearityErrThreshold).ToString();
                    
                    index = cboxPreFitDegree.FindString((JsonConfigInfo.configInfo.PressureFitDegree).ToString());
                    if (index != -1)
                    {
                        cboxPreFitDegree.SelectedIndex = index;
                    }
                    else
                    {
                        _bConfigInfoIsOK = false;
                        MessageBox.Show("参数\"压力拟合阶数\"不在配置选项内!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                        return;
                    }

                    index = cboxTempFitDegree.FindString((JsonConfigInfo.configInfo.TemperatureFitDegree).ToString());
                    if (index != -1)
                    {
                        cboxTempFitDegree.SelectedIndex = index;
                    }
                    else
                    {
                        _bConfigInfoIsOK = false;
                        MessageBox.Show("参数\"温度拟合阶数\"不在配置选项内!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                        return;
                    }

                    UpdateTransferLongAddrAndSN();
                    UpdateConfigInfoToContols();

                    string jsonFilePath = Path.Combine(_exePath, "result", JsonConfigInfo.configInfo.OrderSerialNumber);
                    // update treeViewLoadData
                    LoadJsonFilesToTreeView(jsonFilePath);
                    // update data fit listViewFitData
                    UpdateSrcDataAndFitTargetDataGUI(jsonFilePath, true);

                    _bConfigInfoIsOK = true;

                    AutoCaliUpdCaliStatusToUI();

                    UpdExcelTitle();

                    RetestUpdDataToUI();
                }
                catch (Exception ex)
                {
                    _bConfigInfoIsOK = false;
                    MessageBox.Show("加载配置信息错误: " + ex.Message, "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                }
            }
        }

        private void RetestUpdDataToUI()
        {
            double equalPressure = (double)(numericConfigRangeUp.Value - numericConfigRangeDown.Value) / JsonConfigInfo.configInfo.EqualVal;
            txtBoxRetestPre1.Text = ((double)numericConfigRangeDown.Value).ToString() + "kPa";
            txtBoxRetestPre2.Text = ((double)numericConfigRangeDown.Value + equalPressure).ToString() + "kPa";
            txtBoxRetestPre3.Text = ((double)numericConfigRangeDown.Value + equalPressure * 2).ToString() + "kPa";
            txtBoxRetestPre4.Text = ((double)numericConfigRangeDown.Value + equalPressure * 3).ToString() + "kPa";
            txtBoxRetestPre5.Text = ((double)numericConfigRangeDown.Value + equalPressure * 4).ToString() + "kPa";
            txtBoxRetestPre6.Text = ((double)numericConfigRangeDown.Value + equalPressure * 5).ToString() + "kPa";
            txtBoxRetestPre7.Text = ((double)numericConfigRangeDown.Value + equalPressure * 6).ToString() + "kPa";
            txtBoxRetestPre8.Text = ((double)numericConfigRangeDown.Value + equalPressure * 7).ToString() + "kPa";
            txtBoxRetestPre9.Text = ((double)numericConfigRangeDown.Value + equalPressure * 8).ToString() + "kPa";
        }

        private void UpdateConfigInfoToContols()
        {
            radBtnTemp1.Text = JsonConfigInfo.configInfo.Temperature1;
            radBtnTemp2.Text = JsonConfigInfo.configInfo.Temperature2;
            radBtnTemp3.Text = JsonConfigInfo.configInfo.Temperature3;
            radBtnTemp4.Text = JsonConfigInfo.configInfo.Temperature4;
            radBtnTemp5.Text = JsonConfigInfo.configInfo.Temperature5;
            radBtnTemp6.Text = JsonConfigInfo.configInfo.Temperature6;

            double equalPressure = (double)(numericConfigRangeUp.Value - numericConfigRangeDown.Value) / JsonConfigInfo.configInfo.EqualVal;
            labelPressure1.Text = ((double)numericConfigRangeDown.Value).ToString() + "kPa";
            labelPressure2.Text = ((double)numericConfigRangeDown.Value + equalPressure).ToString() + "kPa";
            labelPressure3.Text = ((double)numericConfigRangeDown.Value + equalPressure * 2).ToString() + "kPa";
            labelPressure4.Text = ((double)numericConfigRangeDown.Value + equalPressure * 3).ToString() + "kPa";
            labelPressure5.Text = ((double)numericConfigRangeDown.Value + equalPressure * 4).ToString() + "kPa";
            labelPressure6.Text = ((double)numericConfigRangeDown.Value + equalPressure * 5).ToString() + "kPa";
            labelPressure7.Text = ((double)numericConfigRangeDown.Value + equalPressure * 6).ToString() + "kPa";
            labelPressure8.Text = ((double)numericConfigRangeDown.Value + equalPressure * 7).ToString() + "kPa";
            labelPressure9.Text = ((double)numericConfigRangeDown.Value + equalPressure * 8).ToString() + "kPa";
        }

        private void UpdateFitTargetDataControl()
        {
            string[] temperature = new string[8] {
                JsonConfigInfo.configInfo.Temperature1, JsonConfigInfo.configInfo.Temperature2,
                JsonConfigInfo.configInfo.Temperature3, JsonConfigInfo.configInfo.Temperature4,
                JsonConfigInfo.configInfo.Temperature5, JsonConfigInfo.configInfo.Temperature6,
                JsonConfigInfo.configInfo.Temperature7, JsonConfigInfo.configInfo.Temperature8,
            };

            string[] pressure = new string[9]
            {
                labelPressure1.Text, labelPressure2.Text, labelPressure3.Text, labelPressure4.Text, labelPressure5.Text,
                labelPressure6.Text, labelPressure7.Text, labelPressure8.Text, labelPressure9.Text,
            };   

            ListViewGroupCollection listViewGroups = listViewFitData.Groups;

            listViewFitData.Items.Clear();

            for (int i = 0; i < 32; i++)
            {
                for (int tempPoints = 0; tempPoints < JsonConfigInfo.configInfo.TemperaturePoints; tempPoints++)
                {
                    for (int prePoints = 0; prePoints < (JsonConfigInfo.configInfo.EqualVal + 1); prePoints++)
                    {
                        ListViewItem item = new ListViewItem();

                        item.Group = listViewGroups[i];
                        item.Text = temperature[tempPoints];

                        item.SubItems.Add(pressure[prePoints]);
                        item.SubItems.Add("0");
                        item.SubItems.Add("0");
                        item.SubItems.Add("0");

                        listViewFitData.Items.Add(item);
                    }
                }

                for (int j = 0; j < JsonConfigInfo.configInfo.TemperaturePoints; j++)
                {
                    ListViewItem item1 = new ListViewItem();
                    item1.Group = listViewGroups[i];
                    item1.SubItems.Add(temperature[j]);
                    item1.SubItems.Add("0");
                    item1.SubItems.Add("0");
                    item1.SubItems.Add("0");

                    listViewFitData.Items.Add(item1);
                }
            }
        }

        private void UpdateTransferLongAddrAndSN()
        {
            TextBox[] txtBoxLongAddrArry = new TextBox[32]
            {
                txtBoxTransLongAddr1, txtBoxTransLongAddr2, txtBoxTransLongAddr3, txtBoxTransLongAddr4, txtBoxTransLongAddr5,
                txtBoxTransLongAddr6, txtBoxTransLongAddr7, txtBoxTransLongAddr8, txtBoxTransLongAddr9, txtBoxTransLongAddr10,
                txtBoxTransLongAddr11, txtBoxTransLongAddr12, txtBoxTransLongAddr13, txtBoxTransLongAddr14, txtBoxTransLongAddr15, 
                txtBoxTransLongAddr16, txtBoxTransLongAddr17, txtBoxTransLongAddr18, txtBoxTransLongAddr19, txtBoxTransLongAddr20,
                txtBoxTransLongAddr21, txtBoxTransLongAddr22, txtBoxTransLongAddr23, txtBoxTransLongAddr24, txtBoxTransLongAddr25,
                txtBoxTransLongAddr26, txtBoxTransLongAddr27, txtBoxTransLongAddr28, txtBoxTransLongAddr29, txtBoxTransLongAddr30,
                txtBoxTransLongAddr31, txtBoxTransLongAddr32
            };

            TextBox[] txtBoxSNArry = new TextBox[32]
            {
                txtBoxTransSN1, txtBoxTransSN2, txtBoxTransSN3, txtBoxTransSN4, txtBoxTransSN5, txtBoxTransSN6, txtBoxTransSN7,
                txtBoxTransSN8, txtBoxTransSN9, txtBoxTransSN10, txtBoxTransSN11, txtBoxTransSN12, txtBoxTransSN13, txtBoxTransSN14, 
                txtBoxTransSN15, txtBoxTransSN16, txtBoxTransSN17, txtBoxTransSN18, txtBoxTransSN19, txtBoxTransSN20,
                txtBoxTransSN21, txtBoxTransSN22, txtBoxTransSN23, txtBoxTransSN24, txtBoxTransSN25, txtBoxTransSN26, txtBoxTransSN27,
                txtBoxTransSN28, txtBoxTransSN29, txtBoxTransSN30, txtBoxTransSN31, txtBoxTransSN32
            };

            for (byte i = 0; i < 32; i++)
            {
                if (JsonConfigInfo.configInfo.transducersInfo[i].Status != false)
                {
                    txtBoxLongAddrArry[i].Text = (JsonConfigInfo.configInfo.transducersInfo[i].LongAddress).ToString();
                    txtBoxSNArry[i].Text = JsonConfigInfo.configInfo.transducersInfo[i].SN;

                    gCheckBoxDevsSelectedAry[i].Checked = true;
                }
            }
        }

        private void UpdateConfigInfo()
        {
            TextBox[] txtBoxArryLongAddr = new TextBox[32]
            {
                txtBoxTransLongAddr1, txtBoxTransLongAddr2, txtBoxTransLongAddr3, txtBoxTransLongAddr4,
                txtBoxTransLongAddr5, txtBoxTransLongAddr6, txtBoxTransLongAddr7, txtBoxTransLongAddr8,
                txtBoxTransLongAddr9, txtBoxTransLongAddr10, txtBoxTransLongAddr11, txtBoxTransLongAddr12,
                txtBoxTransLongAddr13, txtBoxTransLongAddr14, txtBoxTransLongAddr15, txtBoxTransLongAddr16,
                txtBoxTransLongAddr17, txtBoxTransLongAddr18, txtBoxTransLongAddr19, txtBoxTransLongAddr20,
                txtBoxTransLongAddr21, txtBoxTransLongAddr22, txtBoxTransLongAddr23, txtBoxTransLongAddr24,
                txtBoxTransLongAddr25, txtBoxTransLongAddr26, txtBoxTransLongAddr27, txtBoxTransLongAddr28,
                txtBoxTransLongAddr29, txtBoxTransLongAddr30, txtBoxTransLongAddr31, txtBoxTransLongAddr32,
            };

            TextBox[] txtBoxArrySN = new TextBox[32]
            {
                txtBoxTransSN1, txtBoxTransSN2, txtBoxTransSN3, txtBoxTransSN4, txtBoxTransSN5,
                txtBoxTransSN6, txtBoxTransSN7, txtBoxTransSN8, txtBoxTransSN9, txtBoxTransSN10, txtBoxTransSN11,
                txtBoxTransSN12, txtBoxTransSN13, txtBoxTransSN14, txtBoxTransSN15, txtBoxTransSN16,
                txtBoxTransSN17, txtBoxTransSN18, txtBoxTransSN19, txtBoxTransSN20, txtBoxTransSN21,
                txtBoxTransSN22, txtBoxTransSN23, txtBoxTransSN24, txtBoxTransSN25, txtBoxTransSN26, txtBoxTransSN27,
                txtBoxTransSN28, txtBoxTransSN29, txtBoxTransSN30, txtBoxTransSN31, txtBoxTransSN32,
            };

            CheckBox[] chkBoxTrasnducer = new CheckBox[32]
                {
                    chkBoxTransfer1, chkBoxTransfer2, chkBoxTransfer3, chkBoxTransfer4, chkBoxTransfer5,
                    chkBoxTransfer6, chkBoxTransfer7, chkBoxTransfer8, chkBoxTransfer9, chkBoxTransfer10, chkBoxTransfer11,
                    chkBoxTransfer12, chkBoxTransfer13, chkBoxTransfer14, chkBoxTransfer15, chkBoxTransfer16,
                    chkBoxTransfer17, chkBoxTransfer18, chkBoxTransfer19, chkBoxTransfer20, chkBoxTransfer21,
                    chkBoxTransfer22, chkBoxTransfer23, chkBoxTransfer24, chkBoxTransfer25, chkBoxTransfer26,
                    chkBoxTransfer27, chkBoxTransfer28, chkBoxTransfer29, chkBoxTransfer30, chkBoxTransfer31, chkBoxTransfer32,
                };


            for (byte i = 0; i < 32; i++)
            {
                if (chkBoxTrasnducer[i].Checked)
                {
                    JsonConfigInfo.configInfo.transducersInfo[i].Status = true;
                    JsonConfigInfo.configInfo.transducersInfo[i].LongAddress = uint.Parse(txtBoxArryLongAddr[i].Text);
                    JsonConfigInfo.configInfo.transducersInfo[i].SN = txtBoxArrySN[i].Text;
                }
            }
        }

        private void listViewFitData_Resize(object sender, EventArgs e)
        {
            AdjustListViewColumnWidthFitData();
        }

        private void btnDataFit_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 32; i++)
            {
                if (gCheckBoxDevsSelectedAry[i].Checked)
                {
                    try
                    {
                        FitPolynomialPressure($"变送器{i + 1}", i);
                    }
                    catch (Exception ex)
                    {
                        SerialPortsBase.PrintMessage("压力拟合操作错误：" + ex.Message);
                        MessageBox.Show($"变送器{i} 压力拟合错误！", "压力拟合错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                        return;
                    }

                    try
                    {
                        FitPolynomialTemperature($"变送器{i + 1}", i);
                    }
                    catch (Exception ex)
                    {
                        SerialPortsBase.PrintMessage("温度拟合操作错误：" + ex.Message);
                        MessageBox.Show($"变送器{i} 温度拟合错误！", "温度拟合错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                        return;
                    }
                }
            }

            SaveFitResults();
        }

        private void FitPolynomialTemperature(string transducerName, int chl)
        {
            int currentTrasnIndx = chl * (JsonConfigInfo.configInfo.TemperaturePoints * (JsonConfigInfo.configInfo.EqualVal + 1) + JsonConfigInfo.configInfo.TemperaturePoints) +
                JsonConfigInfo.configInfo.TemperaturePoints * (JsonConfigInfo.configInfo.EqualVal + 1);

            List<double> targetVal = new List<double>();
            List<double> sensorVal = new List<double>();

            ListView.ListViewItemCollection items = listViewFitData.Items;

            for (byte i = 0; i < JsonConfigInfo.configInfo.TemperaturePoints; i++)
            {
                ListViewItem item = items[currentTrasnIndx + i];

                try
                {
                    targetVal.Add(double.Parse((item.SubItems[1].Text).TrimEnd('℃')) * 1000);
                    sensorVal.Add(double.Parse(item.SubItems[4].Text));
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);

                    return;
                }
            }

            double[] sensorData = sensorVal.ToArray();
            double[] targetData = targetVal.ToArray();

            var p = Fit.Polynomial(sensorData, targetData, 3);

            if (_temperatureCurveCoefficient.ContainsKey(transducerName))
            { 
                _temperatureCurveCoefficient.Remove(transducerName);
            }
            _temperatureCurveCoefficient.Add(transducerName, new double[4] { p[3], p[2], p[1], p[0] });

            _jsonPreAndTempCurveCof.curveInfo[chl].TemperatureStatus = true;
            _jsonPreAndTempCurveCof.curveInfo[chl].temperatureCurve["x^3"] = p[3];
            _jsonPreAndTempCurveCof.curveInfo[chl].temperatureCurve["x^2"] = p[2];
            _jsonPreAndTempCurveCof.curveInfo[chl].temperatureCurve["x^1"] = p[1];
            _jsonPreAndTempCurveCof.curveInfo[chl].temperatureCurve["x^0"] = p[0];

            SerialPortsBase.PrintMessage($"vvvvvvvvvvvvvvvvvvvvvvvvvvvv 温度拟合 {transducerName} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv");
            SerialPortsBase.PrintMessageNoTime($"拟合多项式方程: y = {p[3]} * x^3 + {p[2]} * x^2 + {p[1]} * x + {p[0]}");

            for (int cnt = 0; cnt < sensorData.Length; cnt++)
            {
                double yFit = p[3] * Math.Pow(sensorData[cnt], 3) + p[2] * Math.Pow(sensorData[cnt], 2) + p[1] * sensorData[cnt] + p[0];
                SerialPortsBase.PrintMessageNoTime($"x = {sensorData[cnt]}, y = {targetData[cnt]}, yFit = {yFit}");
            }
            SerialPortsBase.PrintMessage($"^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 温度拟合 {transducerName} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
            SerialPortsBase.PrintMessageNoTime("\r\n");
        }

        private string GetTemperatureStringByIdx(int idx)
        {
            string[] temperatureStr = new string[8]
            {
                labelPressure1.Text, labelPressure2.Text, labelPressure3.Text, labelPressure4.Text,
                labelPressure5.Text, labelPressure6.Text, labelPressure7.Text, labelPressure8.Text,
            };

            return temperatureStr[idx];
        }

        private int GetTemperatureIdxByString(string temperature)
        {
            string[] temperatureStr = new string[8]
            {
                labelPressure1.Text, labelPressure2.Text, labelPressure3.Text, labelPressure4.Text,
                labelPressure5.Text, labelPressure6.Text, labelPressure7.Text, labelPressure8.Text,
            };

            int idx = 0;

            for (int i = 0; i < temperatureStr.Length; i++)
            {
                if (temperature == temperatureStr[i])
                {
                    idx = i;
                    break;
                }
            }

            return idx;
        }

        private void FitPolynomialPressure(string transducerName, int chl)
        {
            int currentTrasnIndx = chl * (JsonConfigInfo.configInfo.TemperaturePoints * (JsonConfigInfo.configInfo.EqualVal + 1) + JsonConfigInfo.configInfo.TemperaturePoints);

            List<double> targetVal = new List<double>();
            List<double> sensorVal = new List<double>();

            for (byte i = 0; i < JsonConfigInfo.configInfo.TemperaturePoints; i++)
            {
                targetVal.Clear();
                sensorVal.Clear();

                ListView.ListViewItemCollection items = listViewFitData.Items;
                string temperature = null;

                temperature = items[currentTrasnIndx + i * (JsonConfigInfo.configInfo.EqualVal + 1)].SubItems[0].Text;

                for (int j = 0; j < (JsonConfigInfo.configInfo.EqualVal + 1); j++)
                {
                    ListViewItem item = items[currentTrasnIndx + i * (JsonConfigInfo.configInfo.EqualVal + 1) + j];

                    try
                    {
                        string targetStr = item.SubItems[1].Text;

                        if (targetStr.EndsWith("kPa"))
                        {
                            targetVal.Add(1000 * double.Parse(targetStr.Substring(0, targetStr.Length - 3)));
                        }
                        else
                        {
                            targetVal.Add(1000 * double.Parse(item.SubItems[1].Text));
                        }

                        sensorVal.Add(double.Parse(item.SubItems[4].Text));
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);

                        return;
                    }
                }

                double[] sensorData = sensorVal.ToArray();
                double[] targetData = targetVal.ToArray();

                var p = Fit.Polynomial(sensorData, targetData, 4);

                if (_pressureCurveCoefficient.ContainsKey((transducerName, GetTemperatureStringByIdx(i))))
                {
                    _pressureCurveCoefficient.Remove((transducerName, GetTemperatureStringByIdx(i)));
                }
                _pressureCurveCoefficient.Add((transducerName, GetTemperatureStringByIdx(i)), new double[5] { p[4], p[3], p[2], p[1], p[0] });

                _jsonPreAndTempCurveCof.curveInfo[chl].PressureStatus = true;

                switch (i)
                {
                    case 0:
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线1"]["x^4"] = p[4];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线1"]["x^3"] = p[3];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线1"]["x^2"] = p[2];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线1"]["x^1"] = p[1];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线1"]["x^0"] = p[0];
                        break;
                    case 1:
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线2"]["x^4"] = p[4];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线2"]["x^3"] = p[3];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线2"]["x^2"] = p[2];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线2"]["x^1"] = p[1];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线2"]["x^0"] = p[0];
                        break;
                    case 2:
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线3"]["x^4"] = p[4];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线3"]["x^3"] = p[3];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线3"]["x^2"] = p[2];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线3"]["x^1"] = p[1];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线3"]["x^0"] = p[0];
                        break;
                    case 3:
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线4"]["x^4"] = p[4];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线4"]["x^3"] = p[3];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线4"]["x^2"] = p[2];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线4"]["x^1"] = p[1];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线4"]["x^0"] = p[0];
                        break;
                    case 4:
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线5"]["x^4"] = p[4];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线5"]["x^3"] = p[3];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线5"]["x^2"] = p[2];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线5"]["x^1"] = p[1];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线5"]["x^0"] = p[0];
                        break;
                    case 5:
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线6"]["x^4"] = p[4];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线6"]["x^3"] = p[3];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线6"]["x^2"] = p[2];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线6"]["x^1"] = p[1];
                        _jsonPreAndTempCurveCof.curveInfo[chl].pressureCurve["曲线6"]["x^0"] = p[0];
                        break;
                    default:
                        MessageBox.Show("获取压力拟合数据失败!");
                        return;
                }
                
                SerialPortsBase.PrintMessage($"vvvvvvvvvvvvvvvvvvvvvvvvvvvv 压力拟合 {transducerName} 温度点:{temperature} vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv");
                SerialPortsBase.PrintMessageNoTime($"拟合多项式方程: y = {p[4]} * x^4 + {p[3]} * x^3 + {p[2]} * x^2 + {p[1]} * x + {p[0]}");

                for (int cnt = 0; cnt < sensorData.Length; cnt++)
                {
                    double yFit = p[4] * Math.Pow(sensorData[cnt], 4) + p[3] * Math.Pow(sensorData[cnt], 3) + p[2] * Math.Pow(sensorData[cnt], 2) + p[1] * sensorData[cnt] + p[0];
                    SerialPortsBase.PrintMessageNoTime($"x = {sensorData[cnt]}, y = {targetData[cnt]}, yFit = {yFit}");
                }
                SerialPortsBase.PrintMessage($"^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 压力拟合 {transducerName} 温度点:{temperature} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
                SerialPortsBase.PrintMessageNoTime("\r\n");
            }
        }

        private async void btnDownloadCoeff_Click(object sender, EventArgs e)
        {
            bool bFlg = true;

            if (!CheckSerialPortStatus())
            {
                return;
            }

            if (CommandsBase.bHasCMDExecuting == true)
            {
                SerialPortsBase.PrintMessage("有命令正在执行，请稍等！");
                return;
            }

            List<(CMDsGroup, TimeSpan)> CMDsGroups = new List<(CMDsGroup, TimeSpan)>();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl11");

            if (!CheckPressureAndTemperatureCurveCoef())
            {
                return;
            }

            CommandsBase.bHasCMDExecuting = true;

            CloseAllPanelsIndicatorLight();

            string transducerId = null;

            // RGB Alarm
            BatchCaliBoardCMDsSwitchRGB batchBoardSwitchRGB = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Switch G Flashing", RGBSel.eRGB_G_Flashing);

            for (int i = 0; i < 32; i++)
            {
                if (gCheckBoxDevsSelectedAry[i].Checked)
                {
                    transducerId = $"变送器{i + 1}";

                    (List<byte>, List<byte>) curve1 = GetPressureCurveCoefficient(transducerId, 1);
                    (List<byte>, List<byte>) curve2 = GetPressureCurveCoefficient(transducerId, 2);
                    (List<byte>, List<byte>) curve3 = GetPressureCurveCoefficient(transducerId, 3);
                    (List<byte>, List<byte>) curve4 = GetPressureCurveCoefficient(transducerId, 4);
                    (List<byte>, List<byte>) curve5 = GetPressureCurveCoefficient(transducerId, 5);
                    (List<byte>, List<byte>) curve6 = GetPressureCurveCoefficient(transducerId, 6);

                    (List<byte>, List<byte>) temperatureCurve = GetTemperatureCurveCoefficient((byte)i);

                    HART135CustomCommand downLoadPressure1_1 = new HART135CustomCommand(hARTSerialPort_woyatechModem, $"HART#135#81 chl{i + 1} curve1-1", CustomCommandsBase.SETPREFACTOR, data: curve1.Item1);
                    HART135CustomCommand downLoadPressure1_2 = new HART135CustomCommand(hARTSerialPort_woyatechModem, $"HART#135#81 chl{i + 1} curve1-2", CustomCommandsBase.SETPREFACTOR, data: curve1.Item2);

                    HART135CustomCommand downLoadPressure2_1 = new HART135CustomCommand(hARTSerialPort_woyatechModem, $"HART#135#81 chl{i + 1} curve2-1", CustomCommandsBase.SETPREFACTOR, data: curve2.Item1);
                    HART135CustomCommand downLoadPressure2_2 = new HART135CustomCommand(hARTSerialPort_woyatechModem, $"HART#135#81 chl{i + 1} curve2-2", CustomCommandsBase.SETPREFACTOR, data: curve2.Item2);

                    HART135CustomCommand downLoadPressure3_1 = new HART135CustomCommand(hARTSerialPort_woyatechModem, $"HART#135#81 chl{i + 1} curve3-1", CustomCommandsBase.SETPREFACTOR, data: curve3.Item1);
                    HART135CustomCommand downLoadPressure3_2 = new HART135CustomCommand(hARTSerialPort_woyatechModem, $"HART#135#81 chl{i + 1} curve3-2", CustomCommandsBase.SETPREFACTOR, data: curve3.Item2);

                    HART135CustomCommand downLoadPressure4_1 = new HART135CustomCommand(hARTSerialPort_woyatechModem, $"HART#135#81 chl{i + 1} curve4-1", CustomCommandsBase.SETPREFACTOR, data: curve4.Item1);
                    HART135CustomCommand downLoadPressure4_2 = new HART135CustomCommand(hARTSerialPort_woyatechModem, $"HART#135#81 chl{i + 1} curve4-2", CustomCommandsBase.SETPREFACTOR, data: curve4.Item2);

                    HART135CustomCommand downLoadPressure5_1 = new HART135CustomCommand(hARTSerialPort_woyatechModem, $"HART#135#81 chl{i + 1} curve5-1", CustomCommandsBase.SETPREFACTOR, data: curve5.Item1);
                    HART135CustomCommand downLoadPressure5_2 = new HART135CustomCommand(hARTSerialPort_woyatechModem, $"HART#135#81 chl{i + 1} curve5-2", CustomCommandsBase.SETPREFACTOR, data: curve5.Item2);

                    HART135CustomCommand downLoadPressure6_1 = new HART135CustomCommand(hARTSerialPort_woyatechModem, $"HART#135#81 chl{i + 1} curve6-1", CustomCommandsBase.SETPREFACTOR, data: curve6.Item1);
                    HART135CustomCommand downLoadPressure6_2 = new HART135CustomCommand(hARTSerialPort_woyatechModem, $"HART#135#81 chl{i + 1} curve6-2", CustomCommandsBase.SETPREFACTOR, data: curve6.Item2);

                    HART135CustomCommand downLoadTemperature1 = new HART135CustomCommand(hARTSerialPort_woyatechModem, $"HART#135#82 chl{i + 1} Temperature1", CustomCommandsBase.SETTMPFACTOR, data: temperatureCurve.Item1);
                    HART135CustomCommand downLoadTemperature2 = new HART135CustomCommand(hARTSerialPort_woyatechModem, $"HART#135#82 chl{i + 1} Temperature2", CustomCommandsBase.SETTMPFACTOR, data: temperatureCurve.Item2);

                    if (bFlg)
                    {
                        gCMSsGroupsAry[i].AddCommands(
                                new List<(CommandsBase, TimeSpan)>()
                                {
                                    (batchBoardSwitchRGB, TimeSpan.FromSeconds(1)),
                                    (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                                    (downLoadPressure1_1, TimeSpan.FromSeconds(1)),
                                    (downLoadPressure1_2, TimeSpan.FromSeconds(5)),
                                    (downLoadPressure2_1, TimeSpan.FromSeconds(1)),
                                    (downLoadPressure2_2, TimeSpan.FromSeconds(5)),
                                    (downLoadPressure3_1, TimeSpan.FromSeconds(1)),
                                    (downLoadPressure3_2, TimeSpan.FromSeconds(5)),
                                    (downLoadPressure4_1, TimeSpan.FromSeconds(1)),
                                    (downLoadPressure4_2, TimeSpan.FromSeconds(5)),
                                    (downLoadPressure5_1, TimeSpan.FromSeconds(1)),
                                    (downLoadPressure5_2, TimeSpan.FromSeconds(5)),
                                    (downLoadPressure6_1, TimeSpan.FromSeconds(1)),
                                    (downLoadPressure6_2, TimeSpan.FromSeconds(5)),
                                    (downLoadTemperature1, TimeSpan.FromSeconds(1)),
                                    (downLoadTemperature2, TimeSpan.FromSeconds(1)),
                                }
                            );

                        bFlg = false;
                    }
                    else
                    {
                        gCMSsGroupsAry[i].AddCommands(
                                new List<(CommandsBase, TimeSpan)>()
                                {
                                    (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                                    (downLoadPressure1_1, TimeSpan.FromSeconds(1)),
                                    (downLoadPressure1_2, TimeSpan.FromSeconds(5)),
                                    (downLoadPressure2_1, TimeSpan.FromSeconds(1)),
                                    (downLoadPressure2_2, TimeSpan.FromSeconds(5)),
                                    (downLoadPressure3_1, TimeSpan.FromSeconds(1)),
                                    (downLoadPressure3_2, TimeSpan.FromSeconds(5)),
                                    (downLoadPressure4_1, TimeSpan.FromSeconds(1)),
                                    (downLoadPressure4_2, TimeSpan.FromSeconds(5)),
                                    (downLoadPressure5_1, TimeSpan.FromSeconds(1)),
                                    (downLoadPressure5_2, TimeSpan.FromSeconds(5)),
                                    (downLoadPressure6_1, TimeSpan.FromSeconds(1)),
                                    (downLoadPressure6_2, TimeSpan.FromSeconds(5)),
                                    (downLoadTemperature1, TimeSpan.FromSeconds(1)),
                                    (downLoadTemperature2, TimeSpan.FromSeconds(1)),
                                }
                            );
                    }
                   
                    // callbacks
                    object[] args = new object[]
                    {
                        gIndicatorAry[i],
                    };
                    CMDsGroupManager.AddGroupsCallback(i + 1, UpdateIndicator, args);

                    CMDsGroups.Add((gCMSsGroupsAry[i], TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
                }
            }

            CMDsGroupManager.AddGroupsEndCallback(RGBStatusUpdGroupsEndCallback, new object[0]);

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private (List<byte>, List<byte>) GetPressureCurveCoefficient(string transducerName, byte curveId)
        {
            List<byte> data1_1 = new List<byte>();
            List<byte> data1_2 = new List<byte>();
            byte[] bytes;

            data1_1.Add(0x03); // three parameters
            data1_1.Add((byte)(curveId - 1)); // temperature point, -15℃(0x00),0℃(0x01),15℃(0x02),30℃(0x03),45℃(0x04),60℃(0x05)

            data1_2.Add(0x02); // two parameters
            data1_2.Add((byte)(curveId - 1)); // temperature point, -15℃(0x00),0℃(0x01),15℃(0x02),30℃(0x03),45℃(0x04),60℃(0x05)

            // f1x^4 + f2x^3 + f3x^2 + f4x^1 + f4
            for (int i = 0; i < 5; i++)
            {
                bytes = BitConverter.GetBytes(_pressureCurveCoefficient[(transducerName, GetTemperatureStringByIdx(curveId - 1))][i]);
                if (!BitConverter.IsLittleEndian)
                {
                    Array.Reverse(bytes);
                }

                if (i < 3)
                {
                    data1_1.Add((byte)(0x04 - i));
                    data1_1.AddRange(bytes);
                }
                else
                {
                    data1_2.Add((byte)(0x04 - i));
                    data1_2.AddRange(bytes);
                }
            }

            return (data1_1, data1_2);
        }

        private (List<byte>, List<byte>) GetTemperatureCurveCoefficient(byte chl)
        {
            List<byte> data1_1 = new List<byte>();
            List<byte> data1_2 = new List<byte>();
            byte[] bytes;

            data1_1.Add(0x03); // three parameters
            data1_2.Add(0x01); // one parameter

            // x^3
            data1_1.Add(0x03);
            bytes = BitConverter.GetBytes(_jsonPreAndTempCurveCof.curveInfo[chl].temperatureCurve["x^3"]);
            if (!BitConverter.IsLittleEndian)
            {
                Array.Reverse(bytes);
            }
            data1_1.AddRange(bytes);

            // x^2
            data1_1.Add(0x02);
            bytes = BitConverter.GetBytes(_jsonPreAndTempCurveCof.curveInfo[chl].temperatureCurve["x^2"]);
            if (!BitConverter.IsLittleEndian)
            {
                Array.Reverse(bytes);
            }
            data1_1.AddRange(bytes);

            // x^1
            data1_1.Add(0x01);
            bytes = BitConverter.GetBytes(_jsonPreAndTempCurveCof.curveInfo[chl].temperatureCurve["x^1"]);
            if (!BitConverter.IsLittleEndian)
            {
                Array.Reverse(bytes);
            }
            data1_1.AddRange(bytes);

            // x^0
            data1_2.Add(0x00);
            bytes = BitConverter.GetBytes(_jsonPreAndTempCurveCof.curveInfo[chl].temperatureCurve["x^0"]);
            if (!BitConverter.IsLittleEndian)
            {
                Array.Reverse(bytes);
            }
            data1_2.AddRange(bytes);

            return (data1_1, data1_2);
        }

        private bool isTransducersSelected()
        {
            CheckBox[] chksSelected = {
                chkBoxTransfer1, chkBoxTransfer2, chkBoxTransfer3, chkBoxTransfer4, chkBoxTransfer5, chkBoxTransfer6,
                chkBoxTransfer7, chkBoxTransfer8, chkBoxTransfer9, chkBoxTransfer10, chkBoxTransfer11, chkBoxTransfer12,
                chkBoxTransfer13, chkBoxTransfer14, chkBoxTransfer15, chkBoxTransfer16, chkBoxTransfer17, chkBoxTransfer18,
                chkBoxTransfer19, chkBoxTransfer20, chkBoxTransfer21, chkBoxTransfer22, chkBoxTransfer23, chkBoxTransfer24,
                chkBoxTransfer25, chkBoxTransfer26, chkBoxTransfer27, chkBoxTransfer28, chkBoxTransfer29, chkBoxTransfer30,
                chkBoxTransfer31, chkBoxTransfer32,
            };

            bool bSelected = false;

            foreach (var ch in chksSelected)
            {
                if (ch.Checked)
                {
                    bSelected = true;
                    break;
                }
            }

            if (!bSelected)
            {
                MessageBox.Show("未选择变送器！", "警告", buttons:MessageBoxButtons.OK, icon:MessageBoxIcon.Warning);
            }

            return bSelected;
        }

        private void SaveFitResults()
        {
            if (!CheckPressureAndTemperatureCurveCoef())
            {
                return;
            }

            try
            {
                if (_jsonPreAndTempCurveCof.JsonFileSaveInfo(Path.Combine(_exePath, "result", JsonConfigInfo.configInfo.OrderSerialNumber, "PTFittingPolynomials.json")))
                {
                    MessageBox.Show("拟合结果保存成功!", "保存成功", buttons:MessageBoxButtons.OK, icon:MessageBoxIcon.Information);
                }
                else
                {
                    MessageBox.Show("拟合结果保存失败!", "保存失败", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Warning);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("拟合结果保存错误!" + ex.Message, "保存错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
        }

        private bool CheckPressureAndTemperatureCurveCoef()
        {
            for (int i = 0; i < 32; i++)
            {
                if (gCheckBoxDevsSelectedAry[i].Checked)
                {
                    if (!_jsonPreAndTempCurveCof.curveInfo[i].PressureStatus)
                    {
                        MessageBox.Show($"通道{i} 未获取到<压力>曲线系数！", "保存拟合结果失败", buttons:MessageBoxButtons.OK, icon:MessageBoxIcon.Error);
                        return false;
                    }

                    if (!_jsonPreAndTempCurveCof.curveInfo[i].TemperatureStatus)
                    {
                        MessageBox.Show($"通道{i} 未获取到<温度>曲线系数！", "保存拟合结果失败", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                        return false;
                    }
                }
            }

            return true;
        }

        private void radBtnManual_CheckedChanged(object sender, EventArgs e)
        {
            if ((sender as RadioButton).Checked)
            {
               /// txtBoxCurTrans1.ReadOnly = false;
                //txtBoxCurTrans2.ReadOnly = false;
                //txtBoxCurTrans3.ReadOnly = false;
                //txtBoxCurTrans4.ReadOnly = false;
                //txtBoxCurTrans5.ReadOnly = false;
                //txtBoxCurTrans6.ReadOnly = false;
                //txtBoxCurTrans7.ReadOnly = false;
            }
        }

        private void radBtnAuto_CheckedChanged(object sender, EventArgs e)
        {
            if ((sender as RadioButton).Checked)
            {
                //txtBoxCurTrans1.ReadOnly = true;
                //txtBoxCurTrans2.ReadOnly = true;
                //txtBoxCurTrans3.ReadOnly = true;
                //txtBoxCurTrans4.ReadOnly = true;
                //txtBoxCurTrans5.ReadOnly = true;
                //txtBoxCurTrans6.ReadOnly = true;
                //txtBoxCurTrans7.ReadOnly = true;
            }
        }

        private bool CheckSerialPortStatus()
        {
            if (batchBoardSerialPort.SerialPortIsOpen() == false)
            {
                MessageBox.Show("批量板串口未打开！", "警告", buttons:MessageBoxButtons.OK, icon:MessageBoxIcon.Warning);
                return false;
            }

            if (this.cboxCMDsSel.Text != "切换HART通道")
            {
                if (hARTSerialPort_woyatechModem.SerialPortIsOpen() == false)
                {
                    MessageBox.Show("HART串口未打开！", "警告", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Warning);
                    return false;
                }
            }

            return true;
        }

        private async void btnEnterOrExitFixedCurMode_Click(object sender, EventArgs e)
        {
            if (!CheckSerialPortStatus())
            {
                return;
            }

            if (CommandsBase.bHasCMDExecuting == true)
            {
                SerialPortsBase.PrintMessage("有命令正在执行，请稍等！");
                return;
            }

            if (!isTransducersSelected())
            {
                return;
            }

            List<(CMDsGroup, TimeSpan)> CMDsGroups = new List<(CMDsGroup, TimeSpan)>();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chlx");

            CommandsBase.bHasCMDExecuting = true;

            CloseAllPanelsIndicatorLight();

            if (chkBoxTransfer1.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl1", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight1));

                CMDsGroup1.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup1, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer2.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl2", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight2));

                CMDsGroup2.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup2, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer3.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl3", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight3));

                CMDsGroup3.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup3, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer4.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl4", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight4));

                CMDsGroup4.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup4, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer5.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl5", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight5));

                CMDsGroup5.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup5, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer6.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl6", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight6));

                CMDsGroup6.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup6, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer7.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl7", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight7));

                CMDsGroup7.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup7, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer8.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl8", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight8));

                CMDsGroup8.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup8, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer9.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl9", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight9));

                CMDsGroup9.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup9, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer10.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl10", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight10));

                CMDsGroup10.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup10, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer11.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl11", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight11));

                CMDsGroup11.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup11, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer12.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl12", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight12));

                CMDsGroup12.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup12, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer13.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl13", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight13));

                CMDsGroup13.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup13, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer14.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl14", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight14));

                CMDsGroup14.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup14, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer15.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl15", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight15));

                CMDsGroup15.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup15, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer16.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl16", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight16));

                CMDsGroup16.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup16, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer17.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl17", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight17));

                CMDsGroup17.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup17, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer18.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl18", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight18));

                CMDsGroup18.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup18, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer19.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl19", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight19));

                CMDsGroup19.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup19, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer20.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl20", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight20));

                CMDsGroup20.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup20, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer21.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl21", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight21));

                CMDsGroup21.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup21, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer22.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl22", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight22));

                CMDsGroup22.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup22, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer23.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl23", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight23));

                CMDsGroup23.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup23, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer24.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl24", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight24));

                CMDsGroup24.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup24, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer25.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl25", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight25));

                CMDsGroup25.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup25, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer26.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl26", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight26));

                CMDsGroup26.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup26, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer27.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl27", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight27));

                CMDsGroup27.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup27, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer28.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl28", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight28));

                CMDsGroup28.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup28, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer29.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl29", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight29));

                CMDsGroup29.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup29, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer30.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl30", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight30));

                CMDsGroup30.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup30, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer31.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl31", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight31));

                CMDsGroup31.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup31, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            if (chkBoxTransfer32.Checked)
            {
                HART40EnterExitFixedCurrentMode enterExitFixedCurModeCmd = new HART40EnterExitFixedCurrentMode(hARTSerialPort_woyatechModem, "HART#40 chl32", 4.0f);

                hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #40 EE Fixed Current Mode"], new PanelUpdater(panelIndicatorLight32));

                CMDsGroup32.AddCommands(
                    new List<(CommandsBase, TimeSpan)>()
                    {
                        (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)),
                        (enterExitFixedCurModeCmd, TimeSpan.FromSeconds(1)),
                    }
                );

                CMDsGroups.Add((CMDsGroup32, TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
            }

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private void btnSendData_Click(object sender, EventArgs e)
        {
            if (!isTransducersSelected())
            {
                return;
            }
        }

        private void RefreshDeviceList()
        {
            cboxMultiMeterSerialPort.Items.Clear();

            try
            {
                using (var rm = new ResourceManager())
                {
                    IEnumerable<string> resources = rm.Find("?*INSTR");

                    if (resources.Any())
                    {
                        foreach (string resource in resources)
                        {
                            cboxMultiMeterSerialPort.Items.Add(resource);

                            cboxMultiMeterSerialPort.SelectedIndex = 0;
                        }
                    }
                    else
                    {
                        MessageBox.Show("未搜索到任何VISA设备！");
                    }
                }       
            }
            catch (Exception ex)
            {
                MessageBox.Show("查询设备出错：" + ex.Message);
            }
        }

        private void panelMultiMeterSerialPort_Click(object sender, EventArgs e)
        {
            RefreshDeviceList();
        }

        private void btnMultiMeterSerialPortOpen_Click(object sender, EventArgs e)
        {
            try
            {
                if (cboxMultiMeterSerialPort.SelectedItem == null)
                {
                    MessageBox.Show("请选择一个设备！");
                    return;
                }

                string selectedResource = cboxMultiMeterSerialPort.SelectedItem.ToString();

                using (var resourceManager = new ResourceManager())
                {
                    _visaSession = (IMessageBasedSession)resourceManager.Open(selectedResource);
                    SerialPortsBase.PrintMessage("连接成功：" + selectedResource);
                    panelMultiMeterSerialPort.BackColor = Color.IndianRed;

                    _visaSession.FormattedIO.WriteLine("*IDN?");
                    string idnResponse = _visaSession.FormattedIO.ReadLine();
                    SerialPortsBase.PrintMessage("设备信息：" + idnResponse);
                }
                    
            }
            catch (Exception ex)
            {
                MessageBox.Show("连接设备出错：" + ex.Message);
            }
        }

        private void btnMultiMeterSerialPortClose_Click(object sender, EventArgs e)
        {
            _visaSession?.Dispose();
            panelMultiMeterSerialPort.BackColor = Color.DarkGray;
        }

        //private void btnRefresh_Click(object sender, EventArgs e)
        //{
        //    if (string.IsNullOrEmpty(_jsonFolderPath))
        //    {
        //        MessageBox.Show("请先\"加载数据\"！");
        //        return;
        //    }

        //    try
        //    {
        //        LoadJsonFilesToTreeView(_jsonFolderPath);
        //    }
        //    catch (Exception ex)
        //    {
        //        MessageBox.Show("刷新失败：" + ex.Message);
        //    }
        //}

        private async void radBtnTemp_CheckedChanged(object sender, EventArgs e)
        {
            if (isProcessingEvent)
            {
                return;
            }

            if (!temperatureBoxSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("温箱串口未打开。");
                return;
            }

            RadioButton currentRadioButton = (RadioButton)sender;

            if (string.IsNullOrWhiteSpace(currentRadioButton.Text))
            {
                MessageBox.Show("未加载配置文件！", "确认", MessageBoxButtons.OK, MessageBoxIcon.Error);
                currentRadioButton.Checked = false;

                return;
            }

            isProcessingEvent = true;

            if (currentRadioButton.Checked)
            {
                DialogResult result = MessageBox.Show($"确定要切换到温度{currentRadioButton.Text}吗？", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                if (result == DialogResult.No)
                {
                    currentRadioButton.Checked = false;
                    if (_previousRadioButton != null)
                    {
                        _previousRadioButton.Checked = true;
                    }
                }
                else
                {
                    string temperature = null;

                    if (currentRadioButton.Name == "radBtnTemp1")
                    {
                        temperature = JsonConfigInfo.configInfo.Temperature1.TrimEnd('℃');
                    }
                    else if (currentRadioButton.Name == "radBtnTemp2")
                    {
                        temperature = JsonConfigInfo.configInfo.Temperature2.TrimEnd('℃');
                    }
                    else if (currentRadioButton.Name == "radBtnTemp3")
                    {
                        temperature = JsonConfigInfo.configInfo.Temperature3.TrimEnd('℃');
                    }
                    else if (currentRadioButton.Name == "radBtnTemp4")
                    {
                        temperature = JsonConfigInfo.configInfo.Temperature4.TrimEnd('℃');
                    }
                    else if (currentRadioButton.Name == "radBtnTemp5")
                    {
                        temperature = JsonConfigInfo.configInfo.Temperature5.TrimEnd('℃');
                    }
                    else if (currentRadioButton.Name == "radBtnTemp6")
                    {
                        temperature = JsonConfigInfo.configInfo.Temperature6.TrimEnd('℃');
                    }
                    else
                    {
                        temperature = "25";
                    }

                    object[] args = new object[]
                    {
                        temperature,
                     };

                    TemperatureBoxCMDs temperatureBoxCMD = new TemperatureBoxCMDs(temperatureBoxSerialPort, "Set Temperature", TemperatureBoxCMDsType.eSetTemp, args);

                    await temperatureBoxCMD.ExecuteCMD();

                    _previousRadioButton = currentRadioButton;

                    btnUpPressure1.BackColor = Color.Transparent;
                    btnUpPressure2.BackColor = Color.Transparent;
                    btnUpPressure3.BackColor = Color.Transparent;
                    btnUpPressure4.BackColor = Color.Transparent;
                    btnUpPressure5.BackColor = Color.Transparent;
                    btnUpPressure6.BackColor = Color.Transparent;
                    btnUpPressure7.BackColor = Color.Transparent;
                    btnUpPressure8.BackColor = Color.Transparent;
                    btnUpPressure9.BackColor = Color.Transparent;

                    btnDownPressure1.BackColor = Color.Transparent;
                    btnDownPressure2.BackColor = Color.Transparent;
                    btnDownPressure3.BackColor = Color.Transparent;
                    btnDownPressure4.BackColor = Color.Transparent;
                    btnDownPressure5.BackColor = Color.Transparent;
                    btnDownPressure6.BackColor = Color.Transparent;
                    btnDownPressure7.BackColor = Color.Transparent;
                    btnDownPressure8.BackColor = Color.Transparent;
                    btnDownPressure9.BackColor = Color.Transparent;
                }
            }

            isProcessingEvent = false; // 处理完事件后，将标志位重置
        }

        private bool HasSaveOrLoadSystemConfigInfo()
        {
            if (string.IsNullOrWhiteSpace(radBtnTemp1.Text))
            {
                MessageBox.Show("获取 温度点1 错误!", "错误", buttons:MessageBoxButtons.OK ,icon: MessageBoxIcon.Error);

                return false;
            }

            if (string.IsNullOrWhiteSpace(radBtnTemp2.Text))
            {
                MessageBox.Show("获取 温度点2 错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                return false;
            }

            if (string.IsNullOrWhiteSpace(radBtnTemp3.Text))
            {
                MessageBox.Show("获取 温度点3 错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                return false;
            }

            if (string.IsNullOrWhiteSpace(radBtnTemp4.Text))
            {
                MessageBox.Show("获取 温度点4 错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                return false;
            }

            if (string.IsNullOrWhiteSpace(radBtnTemp5.Text))
            {
                MessageBox.Show("获取 温度点5 错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                return false;
            }

            if (string.IsNullOrWhiteSpace(radBtnTemp6.Text))
            {
                MessageBox.Show("获取 温度点6 错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                return false;
            }

            if (string.IsNullOrWhiteSpace(labelPressure1.Text))
            {
                MessageBox.Show("获取 压力点1 错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                return false;
            }

            if (string.IsNullOrWhiteSpace(labelPressure2.Text))
            {
                MessageBox.Show("获取 压力点2 错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                return false;
            }

            if (string.IsNullOrWhiteSpace(labelPressure3.Text))
            {
                MessageBox.Show("获取 压力点3 错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                return false;
            }

            if (string.IsNullOrWhiteSpace(labelPressure4.Text))
            {
                MessageBox.Show("获取 压力点4 错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                return false;
            }

            if (string.IsNullOrWhiteSpace(labelPressure5.Text))
            {
                MessageBox.Show("获取 压力点5 错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                return false;
            }

            if (string.IsNullOrWhiteSpace(labelPressure6.Text))
            {
                MessageBox.Show("获取 压力点6 错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                return false;
            }

            if (string.IsNullOrWhiteSpace(labelPressure7.Text))
            {
                MessageBox.Show("获取 压力点7 错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                return false;
            }

            if (string.IsNullOrWhiteSpace(labelPressure8.Text))
            {
                MessageBox.Show("获取 压力点8 错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                return false;
            }
                
            if (string.IsNullOrWhiteSpace(labelPressure9.Text))
            {
                MessageBox.Show("获取 压力点9 错误!", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                return false;
            }

            return true;
        }

        private void radBtnUPDP_CheckedChanged(object sender, EventArgs e)
        {
            if (((RadioButton)(sender)).Checked)
            {
                radBtnUP1.Checked = sender == radBtnUP1;
                radBtnUP2.Checked = sender == radBtnUP2;
                radBtnUP3.Checked = sender == radBtnUP3;
                radBtnUP4.Checked = sender == radBtnUP4;
                radBtnUP5.Checked = sender == radBtnUP5;
                radBtnUP6.Checked = sender == radBtnUP6;
                radBtnUP7.Checked = sender == radBtnUP7;
                radBtnUP8.Checked = sender == radBtnUP8;
                radBtnUP9.Checked = sender == radBtnUP9;

                radBtnDP1.Checked = sender == radBtnDP1;
                radBtnDP2.Checked = sender == radBtnDP2;
                radBtnDP3.Checked = sender == radBtnDP3;
                radBtnDP4.Checked = sender == radBtnDP4;
                radBtnDP5.Checked = sender == radBtnDP5;
                radBtnDP6.Checked = sender == radBtnDP6;
                radBtnDP7.Checked = sender == radBtnDP7;
                radBtnDP8.Checked = sender == radBtnDP8;
                radBtnDP9.Checked = sender == radBtnDP9;
            }
        }

        private void btnPressureEffeVal_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 32; i++)
            {
                if (JsonConfigInfo.configInfo.transducersInfo[i].Status)
                {
                    int cnt = JsonConfigInfo.configInfo.TemperaturePoints * (JsonConfigInfo.configInfo.EqualVal + 1) + JsonConfigInfo.configInfo.TemperaturePoints;
                    int itemIdx = i * cnt;

                    decimal up = 0;
                    decimal down = 0;
                    double average = 0;
                    string targetVal = null;

                    for (int j = itemIdx; j < (itemIdx + cnt); j++)
                    {
                        if (radioBtnPositive.Checked)
                        {
                            if (decimal.TryParse(listViewFitData.Items[j].SubItems[2].Text, out up))
                            {
                                targetVal = ((double)up).ToString();
                            }
                            else
                            {
                                MessageBox.Show($"[变送器{i}],[{listViewFitData.Items[j].SubItems[0].Text}],[{listViewFitData.Items[j].SubItems[1].Text}]--上行数据({listViewFitData.Items[j].SubItems[2].Text})错误!");
                                return;
                            }
                        }
                        else if (radioBtnReverse.Checked)
                        {
                            if (decimal.TryParse(listViewFitData.Items[j].SubItems[3].Text, out down))
                            {
                                targetVal = ((double)down).ToString();
                            }
                            else
                            {
                                MessageBox.Show($"[变送器{i}],[{listViewFitData.Items[j].SubItems[0].Text}],[{listViewFitData.Items[j].SubItems[1].Text}]--下行数据({listViewFitData.Items[j].SubItems[3].Text})错误!");
                                return;
                            }
                        }
                        else
                        {
                            if (decimal.TryParse(listViewFitData.Items[j].SubItems[2].Text, out up))
                            {

                            }
                            else
                            {
                                MessageBox.Show($"[变送器{i}],[{listViewFitData.Items[j].SubItems[0].Text}],[{listViewFitData.Items[j].SubItems[1].Text}]--上行数据({listViewFitData.Items[j].SubItems[2].Text})错误!");
                                return;
                            }

                            if (decimal.TryParse(listViewFitData.Items[j].SubItems[3].Text, out down))
                            {

                            }
                            else
                            {
                                MessageBox.Show($"[变送器{i}],[{listViewFitData.Items[j].SubItems[0].Text}],[{listViewFitData.Items[j].SubItems[1].Text}]--下行数据({listViewFitData.Items[j].SubItems[3].Text})错误!");
                                return;
                            }

                            average = (double)((up + down) / 2);

                            targetVal = average.ToString();
                        }

                        listViewFitData.Items[j].SubItems[4].Text = targetVal;
                    }
                }
            }
        }

        private async Task UpDownPressureCollection(string sUpOrDown, object sender, bool isClr)
        {
            bool bFlg = true;

            Button button = (Button)sender;
            button.BackColor = Color.Transparent;

            CloseAllPanelsIndicatorLight();

            if (sUpOrDown != "上行程" && sUpOrDown != "下行程")
            {
                return;
            }

            if (!CheckSerialPortStatus())
            {
                return;
            }

            if (!HasSaveOrLoadSystemConfigInfo())
            {
                return;
            }

            if (!isTransducersSelected())
            {
                return;
            }

            if (CommandsBase.bHasCMDExecuting == true)
            {
                MessageBox.Show("有命令正在执行，请稍等！", "警告", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Warning);
                return;
            }

            if (_bConfigInfoIsOK == false)
            {
                MessageBox.Show("未保存配置文件！", "警告", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Warning);
                return;
            }

            CommandsBase.bHasCMDExecuting = true;

            List<(CMDsGroup, TimeSpan)> CMDsGroups = new List<(CMDsGroup, TimeSpan)>();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl");

            HART135CustomCommandFitGetInfo customCMD1 = new HART135CustomCommandFitGetInfo(hARTSerialPort_woyatechModem, "HART#135#08", CustomCommandsBase.GET_INFO, 1, sUpOrDown, listViewSrcData);
            HART135CustomCommandFitGetInfo customCMD2 = new HART135CustomCommandFitGetInfo(hARTSerialPort_woyatechModem, "HART#135#08", CustomCommandsBase.GET_INFO, 2, sUpOrDown, listViewSrcData);
            HART135CustomCommandFitGetInfo customCMD3 = new HART135CustomCommandFitGetInfo(hARTSerialPort_woyatechModem, "HART#135#08", CustomCommandsBase.GET_INFO, 3, sUpOrDown, listViewSrcData);
            HART135CustomCommandFitGetInfo customCMD4 = new HART135CustomCommandFitGetInfo(hARTSerialPort_woyatechModem, "HART#135#08", CustomCommandsBase.GET_INFO, 4, sUpOrDown, listViewSrcData);
            HART135CustomCommandFitGetInfo customCMD5 = new HART135CustomCommandFitGetInfo(hARTSerialPort_woyatechModem, "HART#135#08", CustomCommandsBase.GET_INFO, 5, sUpOrDown, listViewSrcData);
            HART135CustomCommandFitGetInfo customCMD6 = new HART135CustomCommandFitGetInfo(hARTSerialPort_woyatechModem, "HART#135#08", CustomCommandsBase.GET_INFO, 6, sUpOrDown, listViewSrcData);
            HART135CustomCommandFitGetInfo customCMD7 = new HART135CustomCommandFitGetInfo(hARTSerialPort_woyatechModem, "HART#135#08", CustomCommandsBase.GET_INFO, 7, sUpOrDown, listViewSrcData);
            HART135CustomCommandFitGetInfo customCMD8 = new HART135CustomCommandFitGetInfo(hARTSerialPort_woyatechModem, "HART#135#08", CustomCommandsBase.GET_INFO, 8, sUpOrDown, listViewSrcData);
            HART135CustomCommandFitGetInfo customCMD9 = new HART135CustomCommandFitGetInfo(hARTSerialPort_woyatechModem, "HART#135#08", CustomCommandsBase.GET_INFO, 9, sUpOrDown, listViewSrcData);
            HART135CustomCommandFitGetInfo customCMD10 = new HART135CustomCommandFitGetInfo(hARTSerialPort_woyatechModem, "HART#135#08", CustomCommandsBase.GET_INFO, 10, sUpOrDown, listViewSrcData);

            if (sUpOrDown == "上行程")
            {
                hARTSerialPort_woyatechModem.RegisterObservers("HART#135#08--NUM1", new ListViewUpdater(this.listViewSrcData));
                hARTSerialPort_woyatechModem.RegisterObservers("HART#135#08--NUM2", new ListViewUpdater(this.listViewSrcData));
            }
            else
            {
                hARTSerialPort_woyatechModem.RegisterObservers("HART#135#08--NUM3", new ListViewUpdater(this.listViewSrcData));
                hARTSerialPort_woyatechModem.RegisterObservers("HART#135#08--NUM4", new ListViewUpdater(this.listViewSrcData));
            }

            // RGB Alarm
            BatchCaliBoardCMDsSwitchRGB batchBoardSwitchRGB = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Switch G Flashing", RGBSel.eRGB_G_Flashing);

            for (int i = 0; i < 32; i++)
            {
                if (gCheckBoxDevsSelectedAry[i].Checked)
                {
                    if (isClr)
                    {
                        SensorAcquFitValueClr(i + 1, sUpOrDown);
                    }

                    if (bFlg)
                    {
                        gCMSsGroupsAry[i].AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                            {
                                (batchBoardSwitchRGB, TimeSpan.FromSeconds(1)),
                                (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD1, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD2, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD3, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD4, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD5, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD6, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD7, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD8, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD9, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD10, TimeSpan.FromSeconds(0)),
                            }
                        );

                        bFlg = false;
                    }
                    else
                    {
                        gCMSsGroupsAry[i].AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                            {
                                (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD1, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD2, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD3, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD4, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD5, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD6, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD7, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD8, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD9, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (customCMD10, TimeSpan.FromSeconds(0)),
                            }
                        );
                    }

                    // callbacks
                    object[] args = new object[]
                    {
                        gIndicatorAry[i],
                    };
                    CMDsGroupManager.AddGroupsCallback(i + 1, UpdateIndicator, args);

                    CMDsGroups.Add((gCMSsGroupsAry[i], TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
                }  
            }

            // callback
            object[] arg1 = new object[]
            {
                GetCurrentTemperaturePoint(), // temperature
                GetCurrentPressurePoint(sender), // pressure
                sUpOrDown, // "上行程" or "下行程"
                sender,
            };
            object[] arg2 = new object[]
            {
                GetCurrentTemperaturePoint(), // temperature
                GetCurrentPressurePoint(sender), // pressure
                sUpOrDown, // "上行程" or "下行程"
                sender,
            };
            CMDsGroupManager.AddGroupsEndCallback(SaveCollectionData, arg1);
            CMDsGroupManager.AddGroupsEndCallback(UpdateFitDataGUI, arg2);
            CMDsGroupManager.AddGroupsEndCallback(RGBStatusUpdGroupsEndCallback, new object[0]);

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);
            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private void UpdateFitDataGUI(object[] args)
        {
            string jsonFilePath = Path.Combine(_exePath, "result", JsonConfigInfo.configInfo.OrderSerialNumber);

            // update treeViewLoadData
            LoadJsonFilesToTreeView(jsonFilePath);

            // update data fit listViewFitData
            UpdateSrcDataAndFitTargetDataGUI(jsonFilePath, false);
        }

        private void UpdateSrcDataAndFitTargetDataGUI(string folderPath, bool isInitFitDatCtl)
        {
            string searchFilePattern = @"^.*\[(-?\d+℃)\]-\[(-?\d+(\.\d+)?kPa)\].json$";
            List<string> files = GetAllJsonFiles(folderPath);

            string[] temperatureAry = new string[8] 
            {
                JsonConfigInfo.configInfo.Temperature1, JsonConfigInfo.configInfo.Temperature2,
                JsonConfigInfo.configInfo.Temperature3, JsonConfigInfo.configInfo.Temperature4,
                JsonConfigInfo.configInfo.Temperature5, JsonConfigInfo.configInfo.Temperature6,
                JsonConfigInfo.configInfo.Temperature7, JsonConfigInfo.configInfo.Temperature8,
            };

            string[] pressureAry = new string[9]
            {
                labelPressure1.Text, labelPressure2.Text, labelPressure3.Text, labelPressure4.Text, labelPressure5.Text,
                labelPressure6.Text, labelPressure7.Text, labelPressure8.Text, labelPressure9.Text,
            };

            if(isInitFitDatCtl)
            {
                ListViewGroupCollection listViewGroups = listViewFitData.Groups;

                listViewFitData.Items.Clear();

                for (int i = 0; i < 32; i++)
                {
                    for (int tempPoints = 0; tempPoints < JsonConfigInfo.configInfo.TemperaturePoints; tempPoints++)
                    {
                        for (int prePoints = 0; prePoints < (JsonConfigInfo.configInfo.EqualVal + 1); prePoints++)
                        {
                            ListViewItem item = new ListViewItem();

                            item.Group = listViewGroups[i];
                            item.Text = temperatureAry[tempPoints];

                            item.SubItems.Add(pressureAry[prePoints]);
                            item.SubItems.Add("");
                            item.SubItems.Add("");
                            item.SubItems.Add("");

                            listViewFitData.Items.Add(item);
                        }
                    }

                    for (int j = 0; j < JsonConfigInfo.configInfo.TemperaturePoints; j++)
                    {
                        ListViewItem item1 = new ListViewItem();
                        item1.Group = listViewGroups[i];
                        item1.SubItems.Add(temperatureAry[j]);
                        item1.SubItems.Add("");
                        item1.SubItems.Add("");
                        item1.SubItems.Add("");

                        listViewFitData.Items.Add(item1);
                    }
                }
            }

            foreach (string file in files)
            {
                string fileName = Path.GetFileName(file);

                Regex regex = new Regex(searchFilePattern);
                Match match = regex.Match(fileName);

                if (match.Success)
                {
                    string temperature = match.Groups[1].Value;
                    string pressure = match.Groups[2].Value;

                    int temperatureIdx = GetTemeratureIndex(temperature);
                    int pressureIdx = GetPressurePointIndex(pressure);

                    //SerialPortsBase.PrintMessage(temperature + ": " + temperatureIdx.ToString() + ", " + pressure + ": " + pressureIdx.ToString());

                    for (int i = 0; i < 32; i++)
                    {
                        if (JsonConfigInfo.configInfo.transducersInfo[i].Status)
                        {
                            string jsonFileString = File.ReadAllText(file);

                            JsonDevsInfo info = JsonConvert.DeserializeObject<JsonDevsInfo>(jsonFileString);

                            int targetItemIdx = i * (JsonConfigInfo.configInfo.TemperaturePoints * (JsonConfigInfo.configInfo.EqualVal + 1) + JsonConfigInfo.configInfo.TemperaturePoints) +
                                        temperatureIdx * (JsonConfigInfo.configInfo.EqualVal + 1) + pressureIdx;

                            double[] dPressure = new double[10];

                            if ((!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(上行)"][0])) &&
                                (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(上行)"][1])) &&
                                (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(上行)"][2])) &&
                                (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(上行)"][3])) &&
                                (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(上行)"][4])) &&
                                (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(上行)"][5])) &&
                                (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(上行)"][6])) &&
                                (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(上行)"][7])) &&
                                (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(上行)"][8])) &&
                                (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(上行)"][9])))
                            {
                                // 上行压力
                                dPressure[0] = Convert.ToDouble(info.dataInfo[i].Data["压力(上行)"][0]);
                                dPressure[1] = Convert.ToDouble(info.dataInfo[i].Data["压力(上行)"][1]);
                                dPressure[2] = Convert.ToDouble(info.dataInfo[i].Data["压力(上行)"][2]);
                                dPressure[3] = Convert.ToDouble(info.dataInfo[i].Data["压力(上行)"][3]);
                                dPressure[4] = Convert.ToDouble(info.dataInfo[i].Data["压力(上行)"][4]);
                                dPressure[5] = Convert.ToDouble(info.dataInfo[i].Data["压力(上行)"][5]);
                                dPressure[6] = Convert.ToDouble(info.dataInfo[i].Data["压力(上行)"][6]);
                                dPressure[7] = Convert.ToDouble(info.dataInfo[i].Data["压力(上行)"][7]);
                                dPressure[8] = Convert.ToDouble(info.dataInfo[i].Data["压力(上行)"][8]);
                                dPressure[9] = Convert.ToDouble(info.dataInfo[i].Data["压力(上行)"][9]);

                                CalcAverageAndUpdGUI(dPressure, targetItemIdx, 2);

                                // 上行温度, 最后一个压力点也就是满量程时计算温度拟合数据
                                if (pressureAry[JsonConfigInfo.configInfo.EqualVal] == pressure)
                                {
                                    int targetTemperatureItemIdx = i * (JsonConfigInfo.configInfo.TemperaturePoints * (JsonConfigInfo.configInfo.EqualVal + 1) + JsonConfigInfo.configInfo.TemperaturePoints) +
                                        JsonConfigInfo.configInfo.TemperaturePoints * (JsonConfigInfo.configInfo.EqualVal + 1) + temperatureIdx;

                                    dPressure[0] = Convert.ToDouble(info.dataInfo[i].Data["温度(上行)"][0]);
                                    dPressure[1] = Convert.ToDouble(info.dataInfo[i].Data["温度(上行)"][1]);
                                    dPressure[2] = Convert.ToDouble(info.dataInfo[i].Data["温度(上行)"][2]);
                                    dPressure[3] = Convert.ToDouble(info.dataInfo[i].Data["温度(上行)"][3]);
                                    dPressure[4] = Convert.ToDouble(info.dataInfo[i].Data["温度(上行)"][4]);
                                    dPressure[5] = Convert.ToDouble(info.dataInfo[i].Data["温度(上行)"][5]);
                                    dPressure[6] = Convert.ToDouble(info.dataInfo[i].Data["温度(上行)"][6]);
                                    dPressure[7] = Convert.ToDouble(info.dataInfo[i].Data["温度(上行)"][7]);
                                    dPressure[8] = Convert.ToDouble(info.dataInfo[i].Data["温度(上行)"][8]);
                                    dPressure[9] = Convert.ToDouble(info.dataInfo[i].Data["温度(上行)"][9]);

                                    CalcAverageAndUpdGUI(dPressure, targetTemperatureItemIdx, 2);
                                }
                            }
                            //else
                            //{
                            //    MessageBox.Show($"[{temperature}]-[{pressure}]-上行数据不完整!", "警告", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Warning);
                            //    return;
                            //}

                            // 下行压力
                            if((!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(下行)"][0])) &&
                               (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(下行)"][1])) &&
                               (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(下行)"][2])) &&
                               (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(下行)"][3])) &&
                               (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(下行)"][4])) &&
                               (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(下行)"][5])) &&
                               (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(下行)"][6])) &&
                               (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(下行)"][7])) &&
                               (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(下行)"][8])) &&
                               (!string.IsNullOrWhiteSpace(info.dataInfo[i].Data["压力(下行)"][9])))
                            {
                                dPressure[0] = Convert.ToDouble(info.dataInfo[i].Data["压力(下行)"][0]);
                                dPressure[1] = Convert.ToDouble(info.dataInfo[i].Data["压力(下行)"][1]);
                                dPressure[2] = Convert.ToDouble(info.dataInfo[i].Data["压力(下行)"][2]);
                                dPressure[3] = Convert.ToDouble(info.dataInfo[i].Data["压力(下行)"][3]);
                                dPressure[4] = Convert.ToDouble(info.dataInfo[i].Data["压力(下行)"][4]);
                                dPressure[5] = Convert.ToDouble(info.dataInfo[i].Data["压力(下行)"][5]);
                                dPressure[6] = Convert.ToDouble(info.dataInfo[i].Data["压力(下行)"][6]);
                                dPressure[7] = Convert.ToDouble(info.dataInfo[i].Data["压力(下行)"][7]);
                                dPressure[8] = Convert.ToDouble(info.dataInfo[i].Data["压力(下行)"][8]);
                                dPressure[9] = Convert.ToDouble(info.dataInfo[i].Data["压力(下行)"][9]);

                                CalcAverageAndUpdGUI(dPressure, targetItemIdx, 3);

                                // 上行温度, 最后一个压力点也就是满量程时计算温度拟合数据
                                if (pressureAry[JsonConfigInfo.configInfo.EqualVal] == pressure)
                                {
                                    int targetTemperatureItemIdx = i * (JsonConfigInfo.configInfo.TemperaturePoints * (JsonConfigInfo.configInfo.EqualVal + 1) + JsonConfigInfo.configInfo.TemperaturePoints) +
                                        JsonConfigInfo.configInfo.TemperaturePoints * (JsonConfigInfo.configInfo.EqualVal + 1) + temperatureIdx;

                                    dPressure[0] = Convert.ToDouble(info.dataInfo[i].Data["温度(下行)"][0]);
                                    dPressure[1] = Convert.ToDouble(info.dataInfo[i].Data["温度(下行)"][1]);
                                    dPressure[2] = Convert.ToDouble(info.dataInfo[i].Data["温度(下行)"][2]);
                                    dPressure[3] = Convert.ToDouble(info.dataInfo[i].Data["温度(下行)"][3]);
                                    dPressure[4] = Convert.ToDouble(info.dataInfo[i].Data["温度(下行)"][4]);
                                    dPressure[5] = Convert.ToDouble(info.dataInfo[i].Data["温度(下行)"][5]);
                                    dPressure[6] = Convert.ToDouble(info.dataInfo[i].Data["温度(下行)"][6]);
                                    dPressure[7] = Convert.ToDouble(info.dataInfo[i].Data["温度(下行)"][7]);
                                    dPressure[8] = Convert.ToDouble(info.dataInfo[i].Data["温度(下行)"][8]);
                                    dPressure[9] = Convert.ToDouble(info.dataInfo[i].Data["温度(下行)"][9]);

                                    CalcAverageAndUpdGUI(dPressure, targetTemperatureItemIdx, 3);
                                }
                            }
                            //else
                            //{
                            //    MessageBox.Show($"[{temperature}]-[{pressure}]-下行数据不完整!", "警告", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Warning);
                            //    return;
                            //}
                        }
                    }
                }
            }
        }

        private void CalcAverageAndUpdGUI(double[] pressureAry, int targetItemIdx, int targetSubItemIdx)
        {
            double[] middleNums;
            decimal sum = 0;
            decimal average = 0;

            Array.Sort(pressureAry);

            middleNums = pressureAry.Skip(2).Take(6).ToArray();

            sum = 0;

            foreach (double num in middleNums)
            {
                sum += (decimal)num;
            }

            average = sum / middleNums.Length;

            listViewFitData.Items[targetItemIdx].SubItems[targetSubItemIdx].Text = ((double)average).ToString();
        }

        private int GetTemeratureIndex(string temperatureStr)
        {
            string[] temperature = new string[8] {
                JsonConfigInfo.configInfo.Temperature1, JsonConfigInfo.configInfo.Temperature2, JsonConfigInfo.configInfo.Temperature3,
                JsonConfigInfo.configInfo.Temperature4, JsonConfigInfo.configInfo.Temperature5, JsonConfigInfo.configInfo.Temperature6, 
                JsonConfigInfo.configInfo.Temperature7, JsonConfigInfo.configInfo.Temperature8,
            };

            int result = 0xFF;

            for (int i = 0; i < 8; i++)
            {
                if (temperatureStr == temperature[i])
                {
                    result = i;
                    break;
                }
            }

            return result;
        }

        private int GetPressurePointIndex(string pressureStr)
        {
            string[] pressure = new string[9]
            {
                labelPressure1.Text, labelPressure2.Text, labelPressure3.Text, labelPressure4.Text, labelPressure5.Text,
                labelPressure6.Text, labelPressure7.Text, labelPressure8.Text, labelPressure9.Text,
            };

            int result = 0xFF;

            for (int i = 0; i < 9; i++)
            {
                if (pressureStr == pressure[i])
                {
                    result = i;
                    break;
                }
            }

            return result;
        }

        private void SaveCollectionData(object[] args)
        {
            string currentTemperature = (string)args[0];
            string currentPressure = (string)args[1];
            //string sUpOrDown = (string)args[2];
            object sender = args[3];

            string targetFilePath = null;

            string searchPattern = "^.*-\\[" + currentTemperature + "\\]-\\[" + currentPressure + "\\].json$";

            bool bIsFileExist = false;

            JsonDevsInfo info = null;

            string SNFileDir = Path.Combine(_exePath, "result", JsonConfigInfo.configInfo.OrderSerialNumber);
            string TemperatureFileDir = Path.Combine(SNFileDir, currentTemperature);

            try
            {
                if (!Directory.Exists(SNFileDir))
                {
                    Directory.CreateDirectory(SNFileDir);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"创建{SNFileDir}文件夹失败: " + ex.Message, "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                return;
            }

            try
            {
                if (!Directory.Exists(TemperatureFileDir))
                {
                    Directory.CreateDirectory(TemperatureFileDir);
                }
                else
                {
                    string[] files = Directory.GetFiles(TemperatureFileDir);
                    string searchFileName = null;

                    foreach (string file in files)
                    {
                        searchFileName = Path.GetFileName(file);

                        if (Regex.IsMatch(searchFileName, searchPattern))
                        {
                            bIsFileExist = true;
                            targetFilePath = file;
                        }
                    }
                }

                if (bIsFileExist)
                {
                    string jsonFileString = File.ReadAllText(targetFilePath);

                    info = JsonConvert.DeserializeObject<JsonDevsInfo>(jsonFileString);
                }
                else
                {
                    string fileName = $"{DateTime.Now:yyyMMdd_HHmm}-[{currentTemperature}]-[{currentPressure}].json";

                    targetFilePath = Path.Combine(TemperatureFileDir, fileName);

                    info = new JsonDevsInfo()
                    {
                        OrderSerialNumber = JsonConfigInfo.configInfo.OrderSerialNumber,
                        TemperaturePoint = currentTemperature,
                        RangeUp = JsonConfigInfo.configInfo.RangeUp,
                        RangeDown = JsonConfigInfo.configInfo.RangeDown,
                        EqualPoints = JsonConfigInfo.configInfo.EqualVal,
                        CurrentPressure = currentPressure,
                    };
                }
            }
            catch (Exception ex)
            {
                SerialPortsBase.PrintMessage(ex.Message);
                MessageBox.Show(ex.Message, "保存失败", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                return;
            }

            for (int i = 0; i < 32; i++)
            {
                if (gCheckBoxDevsSelectedAry[i].Checked)
                {
                    UpdateJsonCollectionData(ref info, i + 1, sender);
                }
            }

            var settings = new JsonSerializerSettings
            {
                Formatting = Formatting.Indented,
                NullValueHandling = NullValueHandling.Include,
            };

            var jsonString = JsonConvert.SerializeObject(info, settings);

            File.WriteAllText(targetFilePath, jsonString);

            Button button = sender as Button;
            button.BackColor = Color.LightGreen;

            MessageBox.Show("保存数据成功!", "成功", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Information);
        }

        private void UpdateJsonCollectionData(ref JsonDevsInfo info, int chl, object sender)
        {
            int itemIdx = (chl - 1) * 10;

            if ((sender == btnUpPressure1) || (sender == btnUpPressure2) || (sender == btnUpPressure3) || (sender == btnUpPressure4) ||
                (sender == btnUpPressure5) || (sender == btnUpPressure6) || (sender == btnUpPressure7) || (sender == btnUpPressure8) || 
                (sender == btnUpPressure9))
            {
                info.dataInfo[chl - 1].Data["压力(上行)"][0] = listViewSrcData.Items[itemIdx + 0].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][1] = listViewSrcData.Items[itemIdx + 1].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][2] = listViewSrcData.Items[itemIdx + 2].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][3] = listViewSrcData.Items[itemIdx + 3].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][4] = listViewSrcData.Items[itemIdx + 4].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][5] = listViewSrcData.Items[itemIdx + 5].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][6] = listViewSrcData.Items[itemIdx + 6].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][7] = listViewSrcData.Items[itemIdx + 7].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][8] = listViewSrcData.Items[itemIdx + 8].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][9] = listViewSrcData.Items[itemIdx + 9].SubItems[1].Text;

                info.dataInfo[chl - 1].Data["温度(上行)"][0] = listViewSrcData.Items[itemIdx + 0].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][1] = listViewSrcData.Items[itemIdx + 1].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][2] = listViewSrcData.Items[itemIdx + 2].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][3] = listViewSrcData.Items[itemIdx + 3].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][4] = listViewSrcData.Items[itemIdx + 4].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][5] = listViewSrcData.Items[itemIdx + 5].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][6] = listViewSrcData.Items[itemIdx + 6].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][7] = listViewSrcData.Items[itemIdx + 7].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][8] = listViewSrcData.Items[itemIdx + 8].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][9] = listViewSrcData.Items[itemIdx + 9].SubItems[2].Text;
            }
            else
            {
                info.dataInfo[chl - 1].Data["压力(下行)"][0] = listViewSrcData.Items[itemIdx + 0].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][1] = listViewSrcData.Items[itemIdx + 1].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][2] = listViewSrcData.Items[itemIdx + 2].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][3] = listViewSrcData.Items[itemIdx + 3].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][4] = listViewSrcData.Items[itemIdx + 4].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][5] = listViewSrcData.Items[itemIdx + 5].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][6] = listViewSrcData.Items[itemIdx + 6].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][7] = listViewSrcData.Items[itemIdx + 7].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][8] = listViewSrcData.Items[itemIdx + 8].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][9] = listViewSrcData.Items[itemIdx + 9].SubItems[3].Text;

                info.dataInfo[chl - 1].Data["温度(下行)"][0] = listViewSrcData.Items[itemIdx + 0].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][1] = listViewSrcData.Items[itemIdx + 1].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][2] = listViewSrcData.Items[itemIdx + 2].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][3] = listViewSrcData.Items[itemIdx + 3].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][4] = listViewSrcData.Items[itemIdx + 4].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][5] = listViewSrcData.Items[itemIdx + 5].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][6] = listViewSrcData.Items[itemIdx + 6].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][7] = listViewSrcData.Items[itemIdx + 7].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][8] = listViewSrcData.Items[itemIdx + 8].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][9] = listViewSrcData.Items[itemIdx + 9].SubItems[4].Text;
            }
        }

        private string GetCurrentTemperaturePoint()
        {
            string temperature = null;

            if (radBtnTemp1.Checked)
            {
                temperature = radBtnTemp1.Text;
            }
            else if (radBtnTemp2.Checked)
            {
                temperature = radBtnTemp2.Text;
            }
            else if (radBtnTemp3.Checked)
            {
                temperature = radBtnTemp3.Text;
            }
            else if (radBtnTemp4.Checked)
            {
                temperature = radBtnTemp4.Text;
            }
            else if (radBtnTemp5.Checked)
            {
                temperature = radBtnTemp5.Text;
            }
            else if (radBtnTemp6.Checked)
            {
                temperature = radBtnTemp6.Text;
            }

            return temperature;
        }

        private string GetCurrentPressurePoint(object sender)
        { 
            // pressure 1
            if ( sender == btnUpPressure1)
            {
                if (radBtnUP1.Checked)
                {
                    return labelPressure1.Text;
                }
            }

            if (sender == btnDownPressure1)
            {
                if (radBtnDP1.Checked)
                {
                    return labelPressure1.Text;
                }
            }

            // pressure 2
            if (sender == btnUpPressure2)
            {
                if (radBtnUP2.Checked)
                {
                    return labelPressure2.Text;
                }
            }

            if (sender == btnDownPressure2)
            {
                if (radBtnDP2.Checked)
                {
                    return labelPressure2.Text;
                }
            }

            // pressure 3
            if (sender == btnUpPressure3)
            {
                if (radBtnUP3.Checked)
                {
                    return labelPressure3.Text;
                }
            }

            if (sender == btnDownPressure3)
            {
                if (radBtnDP3.Checked)
                {
                    return labelPressure3.Text;
                }
            }

            // pressure 4
            if (sender == btnUpPressure4)
            {
                if (radBtnUP4.Checked)
                {
                    return labelPressure4.Text;
                }
            }

            if (sender == btnDownPressure4)
            {
                if (radBtnDP4.Checked)
                {
                    return labelPressure4.Text;
                }
            }

            // pressure 5
            if (sender == btnUpPressure5)
            {
                if (radBtnUP5.Checked)
                {
                    return labelPressure5.Text;
                }
            }

            if (sender == btnDownPressure5)
            {
                if (radBtnDP5.Checked)
                {
                    return labelPressure5.Text;
                }
            }

            // pressure 6
            if (sender == btnUpPressure6)
            {
                if (radBtnUP6.Checked)
                {
                    return labelPressure6.Text;
                }
            }

            if (sender == btnDownPressure6)
            {
                if (radBtnDP6.Checked)
                {
                    return labelPressure6.Text;
                }
            }

            // pressure 7
            if (sender == btnUpPressure7)
            {
                if (radBtnUP7.Checked)
                {
                    return labelPressure7.Text;
                }
            }

            if (sender == btnDownPressure7)
            {
                if (radBtnDP7.Checked)
                {
                    return labelPressure7.Text;
                }
            }

            // pressure 8
            if (sender == btnUpPressure8)
            {
                if (radBtnUP8.Checked)
                {
                    return labelPressure8.Text;
                }
            }

            if (sender == btnDownPressure8)
            {
                if (radBtnDP8.Checked)
                {
                    return labelPressure8.Text;
                }
            }

            // pressure 9
            if (sender == btnUpPressure9)
            {
                if (radBtnUP9.Checked)
                {
                    return labelPressure9.Text;
                }
            }

            if (sender == btnDownPressure9)
            {
                if (radBtnDP9.Checked)
                {
                    return labelPressure9.Text;
                }
            }

            return null;
        }

        private void SensorAcquFitValueClr(int chl, string sUpOrDown)
        {
            if (chl < 1 || chl > 32)
            {
                return;
            }

            if (sUpOrDown != "上行程" && sUpOrDown != "下行程")
            {
                return;
            }

            int row = (chl - 1) * 10;

            if (sUpOrDown == "上行程")
            {
                this.listViewSrcData.Items[row].SubItems[1].Text = "";
                this.listViewSrcData.Items[row].SubItems[2].Text = "";
                this.listViewSrcData.Items[row + 1].SubItems[1].Text = "";
                this.listViewSrcData.Items[row + 1].SubItems[2].Text = "";
                this.listViewSrcData.Items[row + 2].SubItems[1].Text = "";
                this.listViewSrcData.Items[row + 2].SubItems[2].Text = "";
                this.listViewSrcData.Items[row + 3].SubItems[1].Text = "";
                this.listViewSrcData.Items[row + 3].SubItems[2].Text = "";
                this.listViewSrcData.Items[row + 4].SubItems[1].Text = "";
                this.listViewSrcData.Items[row + 4].SubItems[2].Text = "";
                this.listViewSrcData.Items[row + 5].SubItems[1].Text = "";
                this.listViewSrcData.Items[row + 5].SubItems[2].Text = "";
                this.listViewSrcData.Items[row + 6].SubItems[1].Text = "";
                this.listViewSrcData.Items[row + 6].SubItems[2].Text = "";
                this.listViewSrcData.Items[row + 7].SubItems[1].Text = "";
                this.listViewSrcData.Items[row + 7].SubItems[2].Text = "";                
                this.listViewSrcData.Items[row + 8].SubItems[1].Text = "";
                this.listViewSrcData.Items[row + 8].SubItems[2].Text = "";            
                this.listViewSrcData.Items[row + 9].SubItems[1].Text = "";
                this.listViewSrcData.Items[row + 9].SubItems[2].Text = "";
            }
            else
            {
                this.listViewSrcData.Items[row].SubItems[3].Text = "";
                this.listViewSrcData.Items[row].SubItems[4].Text = "";
                this.listViewSrcData.Items[row + 1].SubItems[3].Text = "";
                this.listViewSrcData.Items[row + 1].SubItems[4].Text = "";
                this.listViewSrcData.Items[row + 2].SubItems[3].Text = "";
                this.listViewSrcData.Items[row + 2].SubItems[4].Text = "";
                this.listViewSrcData.Items[row + 3].SubItems[3].Text = "";
                this.listViewSrcData.Items[row + 3].SubItems[4].Text = "";
                this.listViewSrcData.Items[row + 4].SubItems[3].Text = "";
                this.listViewSrcData.Items[row + 4].SubItems[4].Text = "";
                this.listViewSrcData.Items[row + 5].SubItems[3].Text = "";
                this.listViewSrcData.Items[row + 5].SubItems[4].Text = "";
                this.listViewSrcData.Items[row + 6].SubItems[3].Text = "";
                this.listViewSrcData.Items[row + 6].SubItems[4].Text = "";
                this.listViewSrcData.Items[row + 7].SubItems[3].Text = "";
                this.listViewSrcData.Items[row + 7].SubItems[4].Text = "";
                this.listViewSrcData.Items[row + 8].SubItems[3].Text = "";
                this.listViewSrcData.Items[row + 8].SubItems[4].Text = "";
                this.listViewSrcData.Items[row + 9].SubItems[3].Text = "";
                this.listViewSrcData.Items[row + 9].SubItems[4].Text = "";
            }
        }

        private void SensorAcquFitValueClrAll()
        {
            for (int i = 0; i < 32; i++)
            {
                SensorAcquFitValueClr(i + 1, "上行程");
                SensorAcquFitValueClr(i + 1, "下行程");
            }
        }

        private async void btnUpPressure1_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnUP1.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP1) && (_curCollectionType != CollectionType.eCollectionTypeDP1)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeUP1;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("上行程", sender, isClr);
        }

        private async void btnUpPressure2_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnUP2.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP2) && (_curCollectionType != CollectionType.eCollectionTypeDP2)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeUP2;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("上行程", sender, isClr);
        }

        private async void btnUpPressure3_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnUP3.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP3) && (_curCollectionType != CollectionType.eCollectionTypeDP3)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeUP3;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("上行程", sender, isClr);
        }

        private async void btnUpPressure4_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnUP4.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP4) && (_curCollectionType != CollectionType.eCollectionTypeDP4)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeUP4;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("上行程", sender, isClr);
        }

        private async void btnUpPressure5_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnUP5.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP5) && (_curCollectionType != CollectionType.eCollectionTypeDP5)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeUP5;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("上行程", sender, isClr);
        }

        private async void btnUpPressure6_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnUP6.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP6) && (_curCollectionType != CollectionType.eCollectionTypeDP6)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeUP6;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("上行程", sender, isClr);
        }

        private async void btnUpPressure7_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnUP7.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP7) && (_curCollectionType != CollectionType.eCollectionTypeDP7)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeUP7;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("上行程", sender, isClr);
        }

        private async void btnUpPressure8_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnUP8.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP8) && (_curCollectionType != CollectionType.eCollectionTypeDP8)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeUP8;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("上行程", sender, isClr);
        }

        private async void btnUpPressure9_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnUP9.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP9) && (_curCollectionType != CollectionType.eCollectionTypeDP9)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeUP9;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("上行程", sender, isClr);
        }

        private async void btnDownPressure1_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnDP1.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP1) && (_curCollectionType != CollectionType.eCollectionTypeDP1)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeDP1;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("下行程", sender, isClr);
        }

        private async void btnDownPressure2_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnDP2.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP2) && (_curCollectionType != CollectionType.eCollectionTypeDP2)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeDP2;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("下行程", sender, isClr);
        }

        private async void btnDownPressure3_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnDP3.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP3) && (_curCollectionType != CollectionType.eCollectionTypeDP3)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeDP3;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("下行程", sender, isClr);
        }

        private async void btnDownPressure4_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnDP4.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP4) && (_curCollectionType != CollectionType.eCollectionTypeDP4)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeDP4;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("下行程", sender, isClr);
        }

        private async void btnDownPressure5_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnDP5.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP5) && (_curCollectionType != CollectionType.eCollectionTypeDP5)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeDP5;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("下行程", sender, isClr);
        }

        private async void btnDownPressure6_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnDP6.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP6) && (_curCollectionType != CollectionType.eCollectionTypeDP6)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeDP6;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("下行程", sender, isClr);
        }

        private async void btnDownPressure7_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnDP7.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP7) && (_curCollectionType != CollectionType.eCollectionTypeDP7)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeDP7;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("下行程", sender, isClr);
        }

        private async void btnDownPressure8_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnDP8.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP8) && (_curCollectionType != CollectionType.eCollectionTypeDP8)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeDP8;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("下行程", sender, isClr);
        }

        private async void btnDownPressure9_Click(object sender, EventArgs e)
        {
            bool isClr = true;

            if (!radBtnDP9.Checked)
            {
                return;
            }

            if (((_curCollectionType != CollectionType.eCollectionTypeUP9) && (_curCollectionType != CollectionType.eCollectionTypeDP9)) ||
                (_curCollectionTemperature != GetCurrentTemperaturePoint()))
            {
                SensorAcquFitValueClrAll();

                isClr = false;

                _curCollectionType = CollectionType.eCollectionTypeDP9;
                _curCollectionTemperature = GetCurrentTemperaturePoint();
            }

            await UpDownPressureCollection("下行程", sender, isClr);
        }

        private void WriteSensorRageOrTemperaturePoint_Click(object sender, EventArgs e)
        {
            if (sender == btnSetSensorRange)
            {
                WriteSensorRageOrTemperaturePoint("设置传感器上下限");
            }
            else if (sender == btnSetTemperaturePoint)
            {
                WriteSensorRageOrTemperaturePoint("设置温补点数和温度值");
            }
        }

        private async void btnRGBOff_Click(object sender, EventArgs e)
        {
            string rgbOp = cboxRGBOpSel.Text;
            BatchCaliBoardCMDsSwitchRGB batchBoardSwitchRGB = null;

            if (!batchBoardSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("报警灯控制串口未打开。");
                return;
            }

            try
            {
                if (rgbOp == "ON")
                {
                    if (radBtnR.Checked)
                    {
                        batchBoardSwitchRGB = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Switch R OFF", RGBSel.eRGB_R_ON);
                    }
                    else if (radBtnG.Checked)
                    {
                        batchBoardSwitchRGB = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Switch G OFF", RGBSel.eRGB_G_ON);
                    }
                }
                else if (rgbOp == "OFF")
                {
                    if (radBtnR.Checked)
                    {
                        batchBoardSwitchRGB = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Switch R OFF", RGBSel.eRGB_R_OFF);
                    }
                    else if (radBtnG.Checked)
                    {
                        batchBoardSwitchRGB = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Switch G OFF", RGBSel.eRGB_G_OFF);
                    }
                }
                else if (rgbOp == "闪烁")
                {
                    if (radBtnR.Checked)
                    {
                        batchBoardSwitchRGB = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Switch R Flash", RGBSel.eRGB_R_Flashing);
                    }
                    else if (radBtnG.Checked)
                    {
                        batchBoardSwitchRGB = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Switch G Flash", RGBSel.eRGB_G_Flashing);
                    }
                }

                if (batchBoardSwitchRGB != null)
                {
                    await batchBoardSwitchRGB.ExecuteCMD();
                }
                else
                {
                    return;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"RGB串口错误: {ex.Message}", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
        }

        private async void btnSVOn_Click(object sender, EventArgs e)
        {
            if (!batchBoardSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("电磁阀串口未打开。");
                return;
            }

            try
            {
                BatchCaliBoardCMDsSolenoidValve batchCaliSV = new BatchCaliBoardCMDsSolenoidValve(batchBoardSerialPort, "SV ON", SolenoidValveStatus.eSolenodValueOpen);
                await batchCaliSV.ExecuteCMD();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"电磁阀串口错误: {ex.Message}", "错误", buttons:MessageBoxButtons.OK, icon:MessageBoxIcon.Error);
            }
        }

        private async void btnSVOff_Click(object sender, EventArgs e)
        {
            if (!batchBoardSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("电磁阀串口未打开。");
                return;
            }

            try
            {
                BatchCaliBoardCMDsSolenoidValve batchCaliSV = new BatchCaliBoardCMDsSolenoidValve(batchBoardSerialPort, "SV OFF", SolenoidValveStatus.eSolenodValueClose);
                await batchCaliSV.ExecuteCMD();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"电磁阀串口错误: {ex.Message}", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
        }

        private void btnTempBoxSPortOpen_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(this.cboxTempBoxSPortSel.Text))
            {
                return;
            }

            if (temperatureBoxSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("温箱串口已打开。");
                return;
            }

            if (temperatureBoxSerialPort.Open(this.cboxTempBoxSPortSel.Text))
            {
                PrintfMsg("温箱串口打开成功。");
                this.panelTemperatureBoxSerialPort.BackColor = Color.IndianRed;
            }
            else
            {
                PrintfMsg("温箱串口打开失败。");
                this.panelTemperatureBoxSerialPort.BackColor = Color.DarkGray;
            }
        }

        private void btnTempBoxSPortClose_Click(object sender, EventArgs e)
        {
            if (temperatureBoxSerialPort.SerialPortIsOpen())
            {
                if (temperatureBoxSerialPort.Close())
                {
                    PrintfMsg("批量标定板串口关闭成功。");
                    this.panelTemperatureBoxSerialPort.BackColor = Color.DarkGray;
                }
            }
            else
            {
                PrintfMsg("批量标定板串口已关闭。");
            }
        }

        private void panelTemperatureBoxSerialPort_Click(object sender, EventArgs e)
        {
            UpdateSerialNames(temperatureBoxSerialPort);
        }


        private async void btnTempBoxCmdSetTemp_Click(object sender, EventArgs e)
        {
            if (!temperatureBoxSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("温箱串口未打开。");
                return;
            }

            object[] args = new object[]
            {
                txtTemperatureBoxTemp.Text,
            };

            try
            {
                TemperatureBoxCMDs temperatureBoxCMD = new TemperatureBoxCMDs(temperatureBoxSerialPort, "Set Temperature", TemperatureBoxCMDsType.eSetTemp, args);

                await temperatureBoxCMD.ExecuteCMD();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"温箱串口错误: {ex.Message}", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
        }

        private async void btnTempBoxCmdStopRunning_Click(object sender, EventArgs e)
        {
            if (!temperatureBoxSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("温箱串口未打开。");
                return;
            }

            try
            {
                TemperatureBoxCMDs temperatureBoxCMD = new TemperatureBoxCMDs(temperatureBoxSerialPort, "Stop Running", TemperatureBoxCMDsType.eStopRunning, null);

                await temperatureBoxCMD.ExecuteCMD();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"温箱串口错误: {ex.Message}", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
            
        }

        private async void btnTempBoxCmdStartRunning_Click(object sender, EventArgs e)
        {
            if (!temperatureBoxSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("温箱串口未打开。");
                return;
            }

            try
            {
                TemperatureBoxCMDs temperatureBoxCMD = new TemperatureBoxCMDs(temperatureBoxSerialPort, "Start Running", TemperatureBoxCMDsType.eStartRunning, null);

                await temperatureBoxCMD.ExecuteCMD();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"温箱串口错误: {ex.Message}", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
        }

        private void btnPreControlerSerialPortClose_Click(object sender, EventArgs e)
        {
            if (preControllerSerialPort.SerialPortIsOpen())
            {
                if (preControllerSerialPort.Close())
                {
                    PrintfMsg("压力控制器串口关闭成功。");
                    this.panelPreControlerSerialPort.BackColor = Color.DarkGray;
                }
            }
            else
            {
                PrintfMsg("压力控制器串口已关闭。");
            }
        }

        private void btnPreControlerSerialPortOpen_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(this.cboxPreControlerSerialPort.Text))
            {
                return;
            }

            if (preControllerSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("压力控制器串口已打开。");
                return;
            }

            if (preControllerSerialPort.Open(this.cboxPreControlerSerialPort.Text))
            {
                PrintfMsg("压力控制器串口打开成功。");
                this.panelPreControlerSerialPort.BackColor = Color.IndianRed;
            }
            else
            {
                PrintfMsg("压力控制器串口打开失败。");
                this.panelPreControlerSerialPort.BackColor = Color.DarkGray;
            }
        }

        private void panelPreControlerSerialPort_Click(object sender, EventArgs e)
        {
            UpdateSerialNames(preControllerSerialPort);
        }

        private async void btnLoadCurPre_Click(object sender, EventArgs e)
        {
            if (!preControllerSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("压力控制器串口未打开。");
                return;
            }

            try
            {
                PressureControllerCMDs preCtrlCmd = new PressureControllerCMDs(preControllerSerialPort, "LoadCurrentActualPre", PressureControllerCMDsType.eQueryCurActPressure, null);

                await preCtrlCmd.ExecuteCMD();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"压力控制器串口错误: {ex.Message}", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
        }

        private async void btnPreRelief_Click(object sender, EventArgs e)
        {
            if (!preControllerSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("压力控制器串口未打开。");
                return;
            }

            try
            {
                await AutoCaliPressureControllerSetPressure("0");

                PressureControllerCMDs preCtrlCmd = new PressureControllerCMDs(preControllerSerialPort, "PressureRelief", PressureControllerCMDsType.ePressureRelief, null);

                await preCtrlCmd.ExecuteCMD();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"压力控制器串口错误: {ex.Message}", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
        }

        private async void btnPressurization_Click(object sender, EventArgs e)
        {
            if (!preControllerSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("压力控制器串口未打开。");
                return;
            }

            try
            {
                PressureControllerCMDs preCtrlCmd = new PressureControllerCMDs(preControllerSerialPort, "Pressurization", PressureControllerCMDsType.ePressurization, null);

                await preCtrlCmd.ExecuteCMD();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"压力控制器串口错误: {ex.Message}", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
        }

        private async void btnSetPressureUnit_Click(object sender, EventArgs e)
        {
            if (!preControllerSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("压力控制器串口未打开。");
                return;
            }

            try
            {
                object[] args = new object[]
                {
                    this.cboxPreCtrlUnit.Text,
                };

                PressureControllerCMDs preCtrlCmd = new PressureControllerCMDs(preControllerSerialPort, "SetPressureUnit", PressureControllerCMDsType.eSetUnit, args);

                await preCtrlCmd.ExecuteCMD();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"压力控制器串口错误: {ex.Message}", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
        }

        private async void btnLoadPreUnit_Click(object sender, EventArgs e)
        {
            if (!preControllerSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("压力控制器串口未打开。");
                return;
            }

            try
            {
                PressureControllerCMDs preCtrlCmd = new PressureControllerCMDs(preControllerSerialPort, "LoadPressureUnit", PressureControllerCMDsType.eQueryUnit, null);

                await preCtrlCmd.ExecuteCMD();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"压力控制器串口错误: {ex.Message}", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }   
        }

        private async void btnSetOutputPre_Click(object sender, EventArgs e)
        {
            if (!preControllerSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("压力控制器串口未打开。");
                return;
            }

            try
            {
                object[] args = new object[]
            {
                this.txtBoxOuputPre.Text,
            };

                PressureControllerCMDs preCtrlCmd = new PressureControllerCMDs(preControllerSerialPort, "SetOutputPressure", PressureControllerCMDsType.eSetPressure, args);

                await preCtrlCmd.ExecuteCMD();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"压力控制器串口错误: {ex.Message}", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
        }

        private async void btnLoadOutputPre_Click(object sender, EventArgs e)
        {
            if (!preControllerSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("压力控制器串口未打开。");
                return;
            }

            try
            {
                PressureControllerCMDs preCtrlCmd = new PressureControllerCMDs(preControllerSerialPort, "LoadOutputPressure", PressureControllerCMDsType.eQueryPressure, null);

                await preCtrlCmd.ExecuteCMD();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"压力控制器串口错误: {ex.Message}", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
        }

        private async void SetPressureControllerUnit(string unit)
        {
            object[] args = new object[]
            {
                unit,
            };

            PressureControllerCMDs preCtrlCmd = new PressureControllerCMDs(preControllerSerialPort, "SetPressureUnit", PressureControllerCMDsType.eSetUnit, args);

            await preCtrlCmd.ExecuteCMD();
        }

        private async void btnNegSVOn_Click(object sender, EventArgs e)
        {
            if (!batchBoardSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("电磁阀串口未打开。");
                return;
            }

            try
            {
                BatchCaliBoardCMDsSolenoidValve batchCaliSV = new BatchCaliBoardCMDsSolenoidValve(batchBoardSerialPort, "SV Negative pressure ON", SolenoidValveStatus.eNegPreSolenodValueOpen);
                await batchCaliSV.ExecuteCMD();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"电磁阀串口错误: {ex.Message}", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
            
        }

        private async void btnNegSVOff_Click(object sender, EventArgs e)
        {
            if (!batchBoardSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("电磁阀串口未打开。");
                return;
            }

            try
            {
                BatchCaliBoardCMDsSolenoidValve batchCaliSV = new BatchCaliBoardCMDsSolenoidValve(batchBoardSerialPort, "SV Negative pressure Off", SolenoidValveStatus.eNegPreSolenodValueClose);
                await batchCaliSV.ExecuteCMD();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"电磁阀串口错误: {ex.Message}", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
        }

        private async void btnRetestStart_Click(object sender, EventArgs e)
        {
            bool bFlg = false;

            TextBox[] textBoxes = new TextBox[32]
            {
                txtBoxRetestTrans1, txtBoxRetestTrans2, txtBoxRetestTrans3, txtBoxRetestTrans4, txtBoxRetestTrans5,
                txtBoxRetestTrans6, txtBoxRetestTrans7, txtBoxRetestTrans8, txtBoxRetestTrans9, txtBoxRetestTrans10,
                txtBoxRetestTrans11, txtBoxRetestTrans12, txtBoxRetestTrans13, txtBoxRetestTrans14, txtBoxRetestTrans15,
                txtBoxRetestTrans16, txtBoxRetestTrans17, txtBoxRetestTrans18, txtBoxRetestTrans19, txtBoxRetestTrans20,
                txtBoxRetestTrans21, txtBoxRetestTrans22, txtBoxRetestTrans23, txtBoxRetestTrans24, txtBoxRetestTrans25,
                txtBoxRetestTrans26, txtBoxRetestTrans27, txtBoxRetestTrans28, txtBoxRetestTrans29, txtBoxRetestTrans30,
                txtBoxRetestTrans31, txtBoxRetestTrans32
            };

            TextBox[] showPVTxtBox = new TextBox[32]
            {
                txtBoxPVTrans1, txtBoxPVTrans2, txtBoxPVTrans3, txtBoxPVTrans4, txtBoxPVTrans5, txtBoxPVTrans6,
                txtBoxPVTrans7, txtBoxPVTrans8, txtBoxPVTrans9, txtBoxPVTrans10, txtBoxPVTrans11, txtBoxPVTrans12,
                txtBoxPVTrans13, txtBoxPVTrans14, txtBoxPVTrans15, txtBoxPVTrans16, txtBoxPVTrans17, txtBoxPVTrans18,
                txtBoxPVTrans19, txtBoxPVTrans20, txtBoxPVTrans21, txtBoxPVTrans22, txtBoxPVTrans23, txtBoxPVTrans24,
                txtBoxPVTrans25, txtBoxPVTrans26, txtBoxPVTrans27, txtBoxPVTrans28, txtBoxPVTrans29, txtBoxPVTrans30,
                txtBoxPVTrans31, txtBoxPVTrans32
            };

            TextBox[] showCurrentTxtBox = new TextBox[32]
            {
                txtShowCurrent1, txtShowCurrent2, txtShowCurrent3, txtShowCurrent4, txtShowCurrent5, txtShowCurrent6,
                txtShowCurrent7, txtShowCurrent8, txtShowCurrent9, txtShowCurrent10, txtShowCurrent11, txtShowCurrent12,
                txtShowCurrent13, txtShowCurrent14, txtShowCurrent15, txtShowCurrent16, txtShowCurrent17, txtShowCurrent18,
                txtShowCurrent19, txtShowCurrent20, txtShowCurrent21, txtShowCurrent22, txtShowCurrent23, txtShowCurrent24,
                txtShowCurrent25, txtShowCurrent26, txtShowCurrent27, txtShowCurrent28, txtShowCurrent29, txtShowCurrent30,
                txtShowCurrent31, txtShowCurrent32
            };

            if (!batchBoardSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("批量调试板串口未打开。");
                return;
            }

            if (!hARTSerialPort_woyatechModem.SerialPortIsOpen())
            {
                PrintfMsg("HART通信串口未打开。");
                return;
            }

            if (CommandsBase.bHasCMDExecuting == true)
            {
                SerialPortsBase.PrintMessage("有命令正在执行，请稍等！");
                return;
            }

            CommandsBase.bHasCMDExecuting = true;

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Switch Chl");

            //HART1ReadPrimaryVariable hART1ReadPVCmd = new HART1ReadPrimaryVariable(hARTSerialPort_woyatechModem, "HART#1");
            HART1ReadPrimaryVariable hART1ReadPVCmd = new HART1ReadPrimaryVariableForRetest(hARTSerialPort_woyatechModem, "HART#1");
            //HART2ReadLoopCurrentAndPerOfRge hART2ReadLoopCurrent = new HART2ReadLoopCurrentAndPerOfRge(hARTSerialPort_woyatechModem, "HART#2");
            HART2ReadLoopCurrentAndPerOfRge hART2ReadLoopCurrent = new HART2ReadLoopCurrentAndPerOfRgeForRetest(hARTSerialPort_woyatechModem, "HART#2");

            // RGB Alarm
            BatchCaliBoardCMDsSwitchRGB batchBoardSwitchRGB = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Switch R Flashing", RGBSel.eRGB_G_Flashing);

            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #1 Read PV"], new TextBoxRetestUpdater(textBoxes));
            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #1 Show PV"], new TextBoxShowPVUpdater(showPVTxtBox));
            
            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #2 Read Current"], new TextBoxRetestUpdater(textBoxes));
            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #2 Show Current"], new TextBoxShowPVUpdater(showCurrentTxtBox));

            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #1 Read PV Retest"], new RetestDataExcelUpdater(ref excelHelperCls));
            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #2 Read Current Retest"], new RetestDataExcelUpdater(ref excelHelperCls));

            for (int i = 0; i < 32; i++)
            {
                if (gCheckBoxDevsSelectedAry[i].Checked)
                {
                    if (!bFlg)
                    {
                        gLoopGroupCMDsManager.AddCommandsByChl(i,
                        new List<(CommandsBase, TimeSpan)>()
                            {
                                (batchBoardSwitchRGB, TimeSpan.FromSeconds(0.5)),
                                (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(1)),
                                (hART1ReadPVCmd, TimeSpan.FromSeconds(1)),
                                (hART2ReadLoopCurrent, TimeSpan.FromSeconds(1)),
                            });

                        bFlg = true;
                    }
                    else
                    {
                        gLoopGroupCMDsManager.AddCommandsByChl(i,
                            new List<(CommandsBase, TimeSpan)>()
                                {
                                    (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(0.5)),
                                    (hART1ReadPVCmd, TimeSpan.FromSeconds(1)),
                                    (hART2ReadLoopCurrent, TimeSpan.FromSeconds(1)),
                                });
                    }

                }
            }

            await gLoopGroupCMDsManager.ExecuteAllLoopGroupsAsync();
        }

        private async void btnRetestStop_Click(object sender, EventArgs e)
        {
            gLoopGroupCMDsManager.Stop();

            CommandsBase.bHasCMDExecuting = false;

            try
            {
                BatchCaliBoardCMDsSwitchRGB batchBoardSwitchRGB = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Switch R Flashing", RGBSel.eRGB_G_ON);
                await batchBoardSwitchRGB.ExecuteCMD();
            }
            catch (Exception ex)
            {
                SerialPortsBase.PrintMessage(ex.Message);
            }

            SaveCollectionDataToExcel(ref excelHelperCls);
        }

        private async void MainUI_FormClosing(object sender, FormClosingEventArgs e)
        {
            try
            {
                BatchCaliBoardCMDsSwitchRGB batchBoardSwitchRGB = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Switch R Flashing", RGBSel.eRGB_G_ON);
                await batchBoardSwitchRGB.ExecuteCMD();
            }
            catch (Exception ex)
            {
                SerialPortsBase.PrintMessage(ex.Message);
            }
        }

        private async void btnGetCalFlgs_Click(object sender, EventArgs e)
        {
            if (!CheckSerialPortStatus())
            {
                return;
            }

            CheckBox[,] calFlgCtls = new CheckBox[32,4]
            {
                { chkBoxTempCalFlg1, chkBoxPressureCalFlg1, chkBoxCurrentCalFlg1, chkBoxSensorUDSettingFlg1}, // transducer 1
                { chkBoxTempCalFlg2, chkBoxPressureCalFlg2, chkBoxCurrentCalFlg2, chkBoxSensorUDSettingFlg2}, // transducer 2
                { chkBoxTempCalFlg3, chkBoxPressureCalFlg3, chkBoxCurrentCalFlg3, chkBoxSensorUDSettingFlg3}, // transducer 3
                { chkBoxTempCalFlg4, chkBoxPressureCalFlg4, chkBoxCurrentCalFlg4, chkBoxSensorUDSettingFlg4}, // transducer 4
                { chkBoxTempCalFlg5, chkBoxPressureCalFlg5, chkBoxCurrentCalFlg5, chkBoxSensorUDSettingFlg5}, // transducer 5
                { chkBoxTempCalFlg6, chkBoxPressureCalFlg6, chkBoxCurrentCalFlg6, chkBoxSensorUDSettingFlg6}, // transducer 6
                { chkBoxTempCalFlg7, chkBoxPressureCalFlg7, chkBoxCurrentCalFlg7, chkBoxSensorUDSettingFlg7}, // transducer 7
                { chkBoxTempCalFlg8, chkBoxPressureCalFlg8, chkBoxCurrentCalFlg8, chkBoxSensorUDSettingFlg8}, // transducer 8
                { chkBoxTempCalFlg9, chkBoxPressureCalFlg9, chkBoxCurrentCalFlg9, chkBoxSensorUDSettingFlg9}, // transducer 9
                { chkBoxTempCalFlg10, chkBoxPressureCalFlg10, chkBoxCurrentCalFlg10, chkBoxSensorUDSettingFlg10}, // transducer 10
                { chkBoxTempCalFlg11, chkBoxPressureCalFlg11, chkBoxCurrentCalFlg11, chkBoxSensorUDSettingFlg11}, // transducer 11
                { chkBoxTempCalFlg12, chkBoxPressureCalFlg12, chkBoxCurrentCalFlg12, chkBoxSensorUDSettingFlg12}, // transducer 12
                { chkBoxTempCalFlg13, chkBoxPressureCalFlg13, chkBoxCurrentCalFlg13, chkBoxSensorUDSettingFlg13}, // transducer 13
                { chkBoxTempCalFlg14, chkBoxPressureCalFlg14, chkBoxCurrentCalFlg14, chkBoxSensorUDSettingFlg14}, // transducer 14
                { chkBoxTempCalFlg15, chkBoxPressureCalFlg15, chkBoxCurrentCalFlg15, chkBoxSensorUDSettingFlg15}, // transducer 15
                { chkBoxTempCalFlg16, chkBoxPressureCalFlg16, chkBoxCurrentCalFlg16, chkBoxSensorUDSettingFlg16}, // transducer 16
                { chkBoxTempCalFlg17, chkBoxPressureCalFlg17, chkBoxCurrentCalFlg17, chkBoxSensorUDSettingFlg17}, // transducer 17
                { chkBoxTempCalFlg18, chkBoxPressureCalFlg18, chkBoxCurrentCalFlg18, chkBoxSensorUDSettingFlg18}, // transducer 18
                { chkBoxTempCalFlg19, chkBoxPressureCalFlg19, chkBoxCurrentCalFlg19, chkBoxSensorUDSettingFlg19}, // transducer 19
                { chkBoxTempCalFlg20, chkBoxPressureCalFlg20, chkBoxCurrentCalFlg20, chkBoxSensorUDSettingFlg20}, // transducer 20
                { chkBoxTempCalFlg21, chkBoxPressureCalFlg21, chkBoxCurrentCalFlg21, chkBoxSensorUDSettingFlg21}, // transducer 21
                { chkBoxTempCalFlg22, chkBoxPressureCalFlg22, chkBoxCurrentCalFlg22, chkBoxSensorUDSettingFlg22}, // transducer 22
                { chkBoxTempCalFlg23, chkBoxPressureCalFlg23, chkBoxCurrentCalFlg23, chkBoxSensorUDSettingFlg23}, // transducer 23
                { chkBoxTempCalFlg24, chkBoxPressureCalFlg24, chkBoxCurrentCalFlg24, chkBoxSensorUDSettingFlg24}, // transducer 24
                { chkBoxTempCalFlg25, chkBoxPressureCalFlg25, chkBoxCurrentCalFlg25, chkBoxSensorUDSettingFlg25}, // transducer 25
                { chkBoxTempCalFlg26, chkBoxPressureCalFlg26, chkBoxCurrentCalFlg26, chkBoxSensorUDSettingFlg26}, // transducer 26
                { chkBoxTempCalFlg27, chkBoxPressureCalFlg27, chkBoxCurrentCalFlg27, chkBoxSensorUDSettingFlg27}, // transducer 27
                { chkBoxTempCalFlg28, chkBoxPressureCalFlg28, chkBoxCurrentCalFlg28, chkBoxSensorUDSettingFlg28}, // transducer 28
                { chkBoxTempCalFlg29, chkBoxPressureCalFlg29, chkBoxCurrentCalFlg29, chkBoxSensorUDSettingFlg29}, // transducer 29
                { chkBoxTempCalFlg30, chkBoxPressureCalFlg30, chkBoxCurrentCalFlg30, chkBoxSensorUDSettingFlg30}, // transducer 30
                { chkBoxTempCalFlg31, chkBoxPressureCalFlg31, chkBoxCurrentCalFlg31, chkBoxSensorUDSettingFlg31}, // transducer 31
                { chkBoxTempCalFlg32, chkBoxPressureCalFlg32, chkBoxCurrentCalFlg32, chkBoxSensorUDSettingFlg32}, // transducer 32
            };

            TextBox[] textBoxes = new TextBox[32]
            {
                txtBoxTempPoints1, txtBoxTempPoints2, txtBoxTempPoints3, txtBoxTempPoints4, txtBoxTempPoints5,
                txtBoxTempPoints6, txtBoxTempPoints7, txtBoxTempPoints8, txtBoxTempPoints9, txtBoxTempPoints10,
                txtBoxTempPoints11, txtBoxTempPoints12, txtBoxTempPoints13, txtBoxTempPoints14, txtBoxTempPoints15,
                txtBoxTempPoints16, txtBoxTempPoints17, txtBoxTempPoints18, txtBoxTempPoints19, txtBoxTempPoints20,
                txtBoxTempPoints21, txtBoxTempPoints22, txtBoxTempPoints23, txtBoxTempPoints24, txtBoxTempPoints25,
                txtBoxTempPoints26, txtBoxTempPoints27, txtBoxTempPoints28, txtBoxTempPoints29, txtBoxTempPoints30,
                txtBoxTempPoints31, txtBoxTempPoints32
            };

            for (int i = 0; i < 32; i++)
            {
                calFlgCtls[i, 0].Checked = false;
                calFlgCtls[i, 1].Checked = false;
                calFlgCtls[i, 2].Checked = false;
                calFlgCtls[i, 3].Checked = false;

                textBoxes[i].Clear();
                textBoxes[i].ForeColor = Color.Black;
            }

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Switch Chl");
            HART135CustomCommand customCMD = new HART135CustomCommand(hARTSerialPort_woyatechModem, "HART#135#03", CustomCommandsBase.GET_CAL_FLG);

            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #135#03 Get Flgs"], new TransducerCalFlgUpdater(calFlgCtls));
            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #135#03 Get TPoints Flg"], new TransducerCalFlgTemperaturePointsUpdater(textBoxes));

            for (int i = 0; i < 32; i++)
            {
                if (gCheckBoxDevsSelectedAry[i].Checked)
                {
                    gCMSsGroupsAry[i].AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                    CMDsGroups.Add((gCMSsGroupsAry[i], TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
                }
            }

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private async void btnConfigTransducerRge_Click(object sender, EventArgs e)
        {
            if (!CheckSerialPortStatus())
            {
                return;
            }

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Switch Chl");
            HART35WritePVRangeValues hART35WritePVRgeCmd = new HART35WritePVRangeValues(hARTSerialPort_woyatechModem, "HART#35", 0x0C, (float)numericConfigRangeUp.Value, (float)numericConfigRangeDown.Value);

            for (int i = 0; i < 32; i++)
            {
                if (gCheckBoxDevsSelectedAry[i].Checked)
                {
                    gCMSsGroupsAry[i].AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (hART35WritePVRgeCmd, TimeSpan.FromSeconds(0)),
                        }
                    );

                    CMDsGroups.Add((gCMSsGroupsAry[i], TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
                }
            }

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private async void btnConfigLongAddr_Click(object sender, EventArgs e)
        {
            if (!CheckSerialPortStatus())
            {
                return;
            }

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Switch Chl");
            HART135CustomCommand customCMD = null;

            TextBox[] textBoxes = new TextBox[32]
            {
                txtBoxTransLongAddr1, txtBoxTransLongAddr2, txtBoxTransLongAddr3, txtBoxTransLongAddr4, txtBoxTransLongAddr5,
                txtBoxTransLongAddr6, txtBoxTransLongAddr7, txtBoxTransLongAddr8, txtBoxTransLongAddr9, txtBoxTransLongAddr10,
                txtBoxTransLongAddr11, txtBoxTransLongAddr12, txtBoxTransLongAddr13, txtBoxTransLongAddr14, txtBoxTransLongAddr15,
                txtBoxTransLongAddr16, txtBoxTransLongAddr17, txtBoxTransLongAddr18, txtBoxTransLongAddr19, txtBoxTransLongAddr20,
                txtBoxTransLongAddr21, txtBoxTransLongAddr22, txtBoxTransLongAddr23, txtBoxTransLongAddr24, txtBoxTransLongAddr25,
                txtBoxTransLongAddr26, txtBoxTransLongAddr27, txtBoxTransLongAddr28, txtBoxTransLongAddr29, txtBoxTransLongAddr30,
                txtBoxTransLongAddr31, txtBoxTransLongAddr32
            };

            for (int i = 0; i < 32; i++)
            {
                if (gCheckBoxDevsSelectedAry[i].Checked)
                {
                    int longAddr;

                    if (int.TryParse(textBoxes[i].Text, out longAddr))
                    {
                        if ((longAddr >= 0) && (longAddr <= 16777215))
                        {
                            List<byte> data = new List<byte>();

                            data.Add((byte)(longAddr >> 16));
                            data.Add((byte)(longAddr >> 8));
                            data.Add((byte)(longAddr >> 0));

                            customCMD = new HART135CustomCommand(hARTSerialPort_woyatechModem, "HART#135#89", CustomCommandsBase.SETDEVADDR, data: data);

                            gCMSsGroupsAry[i].AddCommands(
                                new List<(CommandsBase, TimeSpan)>()
                                {
                                    (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                    (customCMD, TimeSpan.FromSeconds(0)),
                                }
                            );

                            CMDsGroups.Add((gCMSsGroupsAry[i], TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
                        }
                        else
                        {
                            SerialPortsBase.PrintMessage($"变送器{i} 长地址范围应该是[0,16777215]");

                            continue;
                        }
                    }
                    else
                    {
                        SerialPortsBase.PrintMessage($"变送器{i} 长地址应为整数，且范围是[0,16777215]");

                        continue;
                    }
                }
            }

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private async void btnBackup_Click(object sender, EventArgs e)
        {
            if (!CheckSerialPortStatus())
            {
                return;
            }

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Switch Chl");
            HART135CustomCommand customCMD = new HART135CustomCommand(hARTSerialPort_woyatechModem, "HART#135#86", CustomCommandsBase.SETFACPARA);

            CheckBox[] checkBoxs = new CheckBox[32]
            {
                chkBoxFacParam1, chkBoxFacParam2, chkBoxFacParam3, chkBoxFacParam4, chkBoxFacParam5, chkBoxFacParam6, chkBoxFacParam7,
                chkBoxFacParam8, chkBoxFacParam9, chkBoxFacParam10, chkBoxFacParam11, chkBoxFacParam12, chkBoxFacParam13, chkBoxFacParam14,
                chkBoxFacParam15, chkBoxFacParam16, chkBoxFacParam17, chkBoxFacParam18, chkBoxFacParam19, chkBoxFacParam20, chkBoxFacParam21,
                chkBoxFacParam22, chkBoxFacParam23, chkBoxFacParam24, chkBoxFacParam25, chkBoxFacParam26, chkBoxFacParam27, chkBoxFacParam28,
                chkBoxFacParam29, chkBoxFacParam30, chkBoxFacParam31, chkBoxFacParam32
            };

            for (int i = 0; i < 32; i++)
            {
                checkBoxs[i].Checked = false;
            }

            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #135#86 Set Fac Param"], new BackupFacParamUpdater(checkBoxs));

            for (int i = 0; i < 32; i++)
            {
                if (gCheckBoxDevsSelectedAry[i].Checked)
                {
                    gCMSsGroupsAry[i].AddCommands(
                        new List<(CommandsBase, TimeSpan)>()
                        {
                            (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            (customCMD, TimeSpan.FromSeconds(0)),
                        }
                    );

                    CMDsGroups.Add((gCMSsGroupsAry[i], TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
                }
            }

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }

        private async void btnCaliStart_Click(object sender, EventArgs e)
        {
            if (!_bConfigInfoIsOK)
            {
                MessageBox.Show("缺少*_Config.json文件", "警告", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Warning);
                return;
            }

            CMDsChlID[] cMDsChlIDs = new CMDsChlID[32] 
            {
                CMDsChlID.eChannel1, CMDsChlID.eChannel2, CMDsChlID.eChannel3, CMDsChlID.eChannel4, CMDsChlID.eChannel5, CMDsChlID.eChannel6, CMDsChlID.eChannel7, CMDsChlID.eChannel8,
                CMDsChlID.eChannel9, CMDsChlID.eChannel10, CMDsChlID.eChannel11, CMDsChlID.eChannel12, CMDsChlID.eChannel13, CMDsChlID.eChannel14, CMDsChlID.eChannel15, CMDsChlID.eChannel16,
                CMDsChlID.eChannel17, CMDsChlID.eChannel18, CMDsChlID.eChannel19, CMDsChlID.eChannel20, CMDsChlID.eChannel21, CMDsChlID.eChannel22, CMDsChlID.eChannel23, CMDsChlID.eChannel24,
                CMDsChlID.eChannel25, CMDsChlID.eChannel26, CMDsChlID.eChannel27, CMDsChlID.eChannel28, CMDsChlID.eChannel29, CMDsChlID.eChannel30, CMDsChlID.eChannel31, CMDsChlID.eChannel32,
            };

            string[] temperature = new string[6] 
            { 
                JsonConfigInfo.configInfo.Temperature1.TrimEnd('℃'), 
                JsonConfigInfo.configInfo.Temperature2.TrimEnd('℃'), 
                JsonConfigInfo.configInfo.Temperature3.TrimEnd('℃'), 
                JsonConfigInfo.configInfo.Temperature4.TrimEnd('℃'), 
                JsonConfigInfo.configInfo.Temperature5.TrimEnd('℃'), 
                JsonConfigInfo.configInfo.Temperature6.TrimEnd('℃'), 
            };

            string[] temperatureWithSymbol = new string[6]
            {
                JsonConfigInfo.configInfo.Temperature1,
                JsonConfigInfo.configInfo.Temperature2,
                JsonConfigInfo.configInfo.Temperature3,
                JsonConfigInfo.configInfo.Temperature4,
                JsonConfigInfo.configInfo.Temperature5,
                JsonConfigInfo.configInfo.Temperature6,
            };

            string[] pressure = new string[9]
            {
                labelPressure1.Text.TrimEnd('k','P','a'),
                labelPressure2.Text.TrimEnd('k','P','a'),
                labelPressure3.Text.TrimEnd('k','P','a'),
                labelPressure4.Text.TrimEnd('k','P','a'),
                labelPressure5.Text.TrimEnd('k','P','a'),
                labelPressure6.Text.TrimEnd('k','P','a'),
                labelPressure7.Text.TrimEnd('k','P','a'),
                labelPressure8.Text.TrimEnd('k','P','a'),
                labelPressure9.Text.TrimEnd('k','P','a'),
            };

            string[] pressureWithSymbol = new string[9]
            {
                labelPressure1.Text,
                labelPressure2.Text,
                labelPressure3.Text,
                labelPressure4.Text,
                labelPressure5.Text,
                labelPressure6.Text,
                labelPressure7.Text,
                labelPressure8.Text,
                labelPressure9.Text,
            };

            string actualPreThreshold = cboxPressureThresholdVal.Text;

            CheckBox[] chkBoxJumpOverTemperature = new CheckBox[6]
            {
                chkBoxJumpOverTemp1, chkBoxJumpOverTemp2, chkBoxJumpOverTemp3, chkBoxJumpOverTemp4, chkBoxJumpOverTemp5, chkBoxJumpOverTemp6
            };

            // 检查串口
            if (!AutoCaliCheckAllSerialPorts())
            {
                AlarmRLedOn();
                MessageBox.Show("有串口未打开！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                return;
            }

            if (CommandsBase.bHasCMDExecuting == true)
            {
                SerialPortsBase.PrintMessage("正在温补，请稍等！");
                return;
            }
            CommandsBase.bHasCMDExecuting = true;

            StartCaliTimeTimer();

            // RGB LED G flashing
            if (!(await AutoCaliAlarmRGBOp(AutoCalibrationCMDsType.eAutoCMD_BatchBoard_LED_G_Flashing)))
            {
                AutoCaliPrintMsgAndLogMsg("警示绿灯未闪烁！");
                CommandsBase.bHasCMDExecuting = false;

                StopCaliTimeTimer();

                return;
            }
            else
            {
                AutoCaliPrintMsgAndLogMsg("******************************* 温补开始 *******************************");
            }

            // 设置log文件保存路劲
            _logger.SetLogDir(Path.Combine(_exePath, "result", JsonConfigInfo.configInfo.OrderSerialNumber, "log"));

            // 1.启动温箱
            if (!(await AutoCaliTemperatureBoxStart()))
            {
                AlarmRLedOn();
                AutoCaliPrintMsgAndLogMsg("1. 温箱启动失败！");
                CommandsBase.bHasCMDExecuting = false;

                MessageBox.Show("1. 温箱启动失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                StopCaliTimeTimer();

                return;
            }
            else
            {
                AutoCaliPrintMsgAndLogMsg("1. 温箱启动成功！");
            }
            await Task.Delay(TimeSpan.FromSeconds(5)); // 延时5s

            if (!AutoCaliCheckAllSerialPorts())
            {
                AlarmRLedOn();
                MessageBox.Show("有串口未打开！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
                CommandsBase.bHasCMDExecuting = false;

                StopCaliTimeTimer();

                return;
            }

            // 2.设置压力控制器单位为kPa
            if (!(await AutoCaliPressureControllerSetUnit("kPa"))) // kPa
            {
                AlarmRLedOn();
                AutoCaliPrintMsgAndLogMsg("2. 设置压力控制器单位（kPa）失败！");
                CommandsBase.bHasCMDExecuting = false;
                MessageBox.Show("2. 设置压力控制器单位（kPa）失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                StopCaliTimeTimer();

                return;
            }
            else
            {
                AutoCaliPrintMsgAndLogMsg("2. 设置压力控制器单位（kPa）成功！");
            }
            await Task.Delay(TimeSpan.FromSeconds(5));

            // 3.查询单位
            if (!(await AutoCaliPressureControllerCheckUnit()))
            {
                AlarmRLedOn();
                AutoCaliPrintMsgAndLogMsg("3. 校验压力控制器单位（kPa）失败, 压力控制器单位不是kPa!");
                CommandsBase.bHasCMDExecuting = false;
                MessageBox.Show("3. 压力控制器单位非 kPa 失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                StopCaliTimeTimer();

                return;
            }
            else
            {
                AutoCaliPrintMsgAndLogMsg("3. 校验压力控制器单位（kPa）成功！");
            }
            await Task.Delay(TimeSpan.FromSeconds(5));

            // 4.设置压力0kPa
            if (!(await AutoCaliPressureControllerSetPressure("0")))
            {
                AlarmRLedOn();
                AutoCaliPrintMsgAndLogMsg("4. 设置0kPa失败！");
                CommandsBase.bHasCMDExecuting = false;
                MessageBox.Show("4. 设置0kPa失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                StopCaliTimeTimer();

                return;
            }
            else
            {
                AutoCaliPrintMsgAndLogMsg("4. 设置0kPa成功！");
            }
            await Task.Delay(TimeSpan.FromSeconds(5));

            // 读变送器拟合数据
            int errorPressure = 0;
            int msgID = 0;

            for (int temperaturePoints = 0; temperaturePoints < 6; temperaturePoints++)
            {
                tabControl1.SelectedTab = tabPage15;

                if (GetTemperatureCaliStatus(temperaturePoints))
                {
                    AutoCaliPrintMsgAndLogMsg($"温度{temperatureWithSymbol[temperaturePoints]}补偿已经完成！");

                    continue;
                }

                msgID = 5 + temperaturePoints;

                // 设置温度
                if (!(await AutoCaliTemperatureBoxSetTemperature(temperature[temperaturePoints])))
                {
                    AlarmRLedOn();
                    AutoCaliPrintMsgAndLogMsg($"{msgID}. 温度{temperature[temperaturePoints]}设置失败！");
                    CommandsBase.bHasCMDExecuting = false;
                    MessageBox.Show($"{msgID}. 温度{temperature[temperaturePoints]}设置失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                    StopCaliTimeTimer();

                    return;
                }
                else
                {
                    AutoCaliPrintMsgAndLogMsg($"{msgID}. 温度{temperature[temperaturePoints]}设置成功！");
                }

                // 压力控制器测量状态
                if (!(await AutoCaliPressureContrillerOutputClose()))
                {
                    AlarmRLedOn();
                    AutoCaliPrintMsgAndLogMsg("压力控制器进入测量状态失败！");
                    CommandsBase.bHasCMDExecuting = false;
                    MessageBox.Show("压力控制器进入测量状态失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                    StopCaliTimeTimer();

                    return;
                }
                else
                {
                    AutoCaliPrintMsgAndLogMsg("压力控制器进入测量状态成功！");
                }

                remainingTimeInSeconds = GetTimeInSeconds();
                countDownTimer.Start();
                AutoCaliPrintMsgAndLogMsg($"温度{temperatureWithSymbol[temperaturePoints]}保温中................................................................................");

                if (chkBoxJumpOverTemperature[temperaturePoints].Checked)
                {
                    await Task.Delay(TimeSpan.FromSeconds(3));
                }
                else
                {
#if false // Test
                remainingTimeInSeconds = 10;
                await Task.Delay(TimeSpan.FromSeconds(remainingTimeInSeconds));
#else
                    await Task.Delay(TimeSpan.FromSeconds(remainingTimeInSeconds));
#endif
                }

                countDownTimer.Stop();

                // 压力控制输出
                if (!(await AutoCaliPressureControllerOutput()))
                {
                    AlarmRLedOn();
                    AutoCaliPrintMsgAndLogMsg("设置压力控制器输出失败！");
                    CommandsBase.bHasCMDExecuting = false;
                    MessageBox.Show("设置压力控制器输出失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                    StopCaliTimeTimer();

                    return;
                }
                else
                {
                    AutoCaliPrintMsgAndLogMsg("设置压力控制器输出成功！");
                }

                // 上行程
                hARTSerialPort_woyatechModem.RegisterObservers("HART#135#08--NUM1", new ListViewUpdater(this.listViewSrcData));
                hARTSerialPort_woyatechModem.RegisterObservers("HART#135#08--NUM2", new ListViewUpdater(this.listViewSrcData));

                object[] args = new object[] 
                {
                    (byte)1,
                    "上行程",
                    this.listViewSrcData,
                };

                AutoCaliPrintMsgAndLogMsg($"********** {msgID}. [{temperatureWithSymbol[temperaturePoints]}] [上行程] 开始采集 **********");

                try
                {
                    tabControl1.SelectedTab = tabPage4;

                    // 打开真空泵
                    if (!(await AutoCaliPumpOpen()))
                    {
                        AlarmRLedOn();
                        AutoCaliPrintMsgAndLogMsg($"{msgID}. 真空泵打开失败！");
                        CommandsBase.bHasCMDExecuting = false;
                        MessageBox.Show($"{msgID}. 真空泵打开失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                        StopCaliTimeTimer();

                        return;
                    }
                    else
                    {
                        AutoCaliPrintMsgAndLogMsg($"{msgID}. 真空泵打开成功！");
                    }

                    for (int pressurePoints = 0; pressurePoints < 9; pressurePoints++)
                    {
                        errorPressure = pressurePoints;

                        AutoCaliPrintMsgAndLogMsg($"上行程--温度{temperatureWithSymbol[temperaturePoints]}, 压力{pressureWithSymbol[pressurePoints]} 开始采集！");

                        // 设置压力
                        if (!(await AutoCaliPressureControllerSetPressure(pressure[pressurePoints])))
                        {
                            AlarmRLedOn();
                            AutoCaliPrintMsgAndLogMsg($"{msgID}. 压力{pressureWithSymbol[pressurePoints]}设置失败！");
                            CommandsBase.bHasCMDExecuting = false;
                            MessageBox.Show($"{msgID}. 压力{pressureWithSymbol[pressurePoints]}设置失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                            StopCaliTimeTimer();

                            return;
                        }
                        else
                        {
                            AutoCaliPrintMsgAndLogMsg($"{msgID}. 压力{pressureWithSymbol[pressurePoints]}设置成功！");
                        }
                        await Task.Delay(TimeSpan.FromSeconds(4));

                        // 校验压力
                        if (!(await AutoCaliCheckCurrentPressure(pressure[pressurePoints], actualPreThreshold)))
                        {
                            AlarmRLedOn();
                            AutoCaliPrintMsgAndLogMsg($"{msgID}. 压力{pressureWithSymbol[pressurePoints]}校验失败！");
                            CommandsBase.bHasCMDExecuting = false;
                            MessageBox.Show($"{msgID}. 压力{pressureWithSymbol[pressurePoints]}校验失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                            StopCaliTimeTimer();

                            return;
                        }
                        else
                        {
                            AutoCaliPrintMsgAndLogMsg($"{msgID}. 压力{pressureWithSymbol[pressurePoints]}校验成功！");
                        }

                        SensorAcquFitValueClrAll();

                        for (int i = 0; i < 32; i++)
                        {
                            if (gCheckBoxDevsSelectedAry[i].Checked)
                            {
                                if (!(await AutoCaliSwitchChannal(cMDsChlIDs[i])))
                                {
                                    AlarmRLedOn();
                                    AutoCaliPrintMsgAndLogMsg($"{msgID}. 切换Channel{i + 1}失败！");
                                    CommandsBase.bHasCMDExecuting = false;
                                    MessageBox.Show($"{msgID}. 切换Channel{i + 1}失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                                    StopCaliTimeTimer();

                                    return;
                                }
                                else
                                {
                                    AutoCaliPrintMsgAndLogMsg($"{msgID}. 切换Channel{i + 1}成功！");
                                }

                                for (int j = 1; j <= 10; j++)
                                {
                                    args[0] = j;

                                    if (!(await AutoCaliGetFitDataInfo(args, j)))
                                    {
                                        AlarmRLedOn();
                                        AutoCaliPrintMsgAndLogMsg($"{msgID}. 上行程-[{temperatureWithSymbol[temperaturePoints]}]-[{pressureWithSymbol[pressurePoints]}]第{j}次采集失败！");
                                        CommandsBase.bHasCMDExecuting = false;
                                        MessageBox.Show($"{msgID}. 上行程-[{temperatureWithSymbol[temperaturePoints]}]-[{pressureWithSymbol[pressurePoints]}]第{j}次采集失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                                        StopCaliTimeTimer();

                                        return;
                                    }
                                    else
                                    {
                                        AutoCaliPrintMsgAndLogMsg($"{msgID}. 上行程-[{temperatureWithSymbol[temperaturePoints]}]-[{pressureWithSymbol[pressurePoints]}]第{j}次采集成功！");
                                    }
                                    await Task.Delay(TimeSpan.FromSeconds(2));
                                }
                            }
                        }

                        (bool flg1, string filePath1) = AutoCaliSaveCollectionData(temperatureWithSymbol[temperaturePoints], pressureWithSymbol[pressurePoints], "上行程");

                        if (!flg1)
                        {
                            AutoCaliPrintMsgAndLogMsg($"{args[1]}-[{temperatureWithSymbol[temperaturePoints]}]-[{pressureWithSymbol[pressurePoints]}], 文件:{filePath1}, 数据保存失败！");
                            CommandsBase.bHasCMDExecuting = false;

                            StopCaliTimeTimer();

                            return;
                        }
                        else
                        {
                            AutoCaliPrintMsgAndLogMsg($"{args[1]}-[{temperatureWithSymbol[temperaturePoints]}]-[{pressureWithSymbol[pressurePoints]}], 文件:{filePath1}, 数据保存成功！");

                            UpdateFitDataGUI(new object[] { });
                        }
                    }
                }
                catch (Exception ex)
                {
                    AutoCaliPrintMsgAndLogMsg($"{args[1]}-[{temperatureWithSymbol[temperaturePoints]}]-[{pressureWithSymbol[errorPressure]}], error:{ex.Message}, 数据采集发生错误！");
                    CommandsBase.bHasCMDExecuting = false;

                    StopCaliTimeTimer();

                    return;
                }      

                // 下行程
                hARTSerialPort_woyatechModem.RegisterObservers("HART#135#08--NUM3", new ListViewUpdater(this.listViewSrcData));
                hARTSerialPort_woyatechModem.RegisterObservers("HART#135#08--NUM4", new ListViewUpdater(this.listViewSrcData));

                args[1] = "下行程";

                AutoCaliPrintMsgAndLogMsg($"********** {msgID}. [{temperatureWithSymbol[temperaturePoints]}] [下行程] 开始采集 **********");

                try
                {
                    for (int pressurePoints = 0; pressurePoints < 9; pressurePoints++)
                    {
                        errorPressure = pressurePoints;

                        AutoCaliPrintMsgAndLogMsg($"下行程--温度{temperatureWithSymbol[temperaturePoints]}, 压力{pressureWithSymbol[pressurePoints]} 开始采集！");

                        // 设置压力
                        if (!(await AutoCaliPressureControllerSetPressure(pressure[8 - pressurePoints])))
                        {
                            AlarmRLedOn();
                            AutoCaliPrintMsgAndLogMsg($"{msgID}. 压力{pressureWithSymbol[8 - pressurePoints]}设置失败！");
                            CommandsBase.bHasCMDExecuting = false;
                            MessageBox.Show($"{msgID}. 压力{pressureWithSymbol[8 - pressurePoints]}设置失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                            StopCaliTimeTimer();

                            return;
                        }
                        else
                        {
                            AutoCaliPrintMsgAndLogMsg($"{msgID}. 压力{pressureWithSymbol[8 - pressurePoints]}设置成功！");
                        }
                        await Task.Delay(TimeSpan.FromSeconds(4));

                        // 校验压力
                        if (!(await AutoCaliCheckCurrentPressure(pressure[8 - pressurePoints], actualPreThreshold)))
                        {
                            AlarmRLedOn();
                            AutoCaliPrintMsgAndLogMsg($"{msgID}. 压力{pressureWithSymbol[8 - pressurePoints]}校验失败！");
                            CommandsBase.bHasCMDExecuting = false;
                            MessageBox.Show($"{msgID}. 压力{pressureWithSymbol[8 - pressurePoints]}校验失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                            StopCaliTimeTimer();

                            return;
                        }
                        else
                        {
                            AutoCaliPrintMsgAndLogMsg($"{msgID}. 压力{pressureWithSymbol[8 - pressurePoints]}校验成功！");
                        }

                        SensorAcquFitValueClrAll();

                        for (int k = 0; k < 32; k++)
                        {
                            if (gCheckBoxDevsSelectedAry[k].Checked)
                            {
                                if (!(await AutoCaliSwitchChannal(cMDsChlIDs[k])))
                                {
                                    AlarmRLedOn();
                                    AutoCaliPrintMsgAndLogMsg($"{msgID}. 切换Channel{k + 1}失败！");
                                    CommandsBase.bHasCMDExecuting = false;
                                    MessageBox.Show($"{msgID}. 切换Channel{k + 1}失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                                    StopCaliTimeTimer();

                                    return;
                                }
                                else
                                {
                                    AutoCaliPrintMsgAndLogMsg($"{msgID}. 切换Channel{k + 1}成功！");
                                }

                                for (int m = 1; m <= 10; m++)
                                {
                                    args[0] = m;

                                    if (!(await AutoCaliGetFitDataInfo(args, m)))
                                    {
                                        AlarmRLedOn();
                                        AutoCaliPrintMsgAndLogMsg($"{msgID}. 下行程-[{temperatureWithSymbol[temperaturePoints]}]-[{pressureWithSymbol[pressurePoints]}]第{m}次采集失败！");
                                        CommandsBase.bHasCMDExecuting = false;
                                        MessageBox.Show($"{msgID}. 下行程-[{temperatureWithSymbol[temperaturePoints]}]-[{pressureWithSymbol[pressurePoints]}]第{m}次采集失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                                        StopCaliTimeTimer();

                                        return;
                                    }
                                    else
                                    {
                                        AutoCaliPrintMsgAndLogMsg($"{msgID}. 下行程-[{temperatureWithSymbol[temperaturePoints]}]-[{pressureWithSymbol[pressurePoints]}]第{m}次采集成功！");
                                    }
                                    await Task.Delay(TimeSpan.FromSeconds(2));
                                }
                            }
                        }

                        (bool flg2, string filePath2) = AutoCaliSaveCollectionData(temperatureWithSymbol[temperaturePoints], pressureWithSymbol[8 - pressurePoints], "下行程");

                        if (!flg2)
                        {
                            AutoCaliPrintMsgAndLogMsg($"{args[1]}-[{temperatureWithSymbol[temperaturePoints]}]-[{pressureWithSymbol[8 - pressurePoints]}], 文件:{filePath2}, 数据保存失败！");
                            CommandsBase.bHasCMDExecuting = false;

                            StopCaliTimeTimer();

                            return;
                        }
                        else
                        {
                            AutoCaliPrintMsgAndLogMsg($"{args[1]}-[{temperatureWithSymbol[temperaturePoints]}]-[{pressureWithSymbol[8 - pressurePoints]}], 文件:{filePath2}, 数据保存成功！");

                            UpdateFitDataGUI(new object[] { });
                        }

                        JsonConfigInfo.configInfo.TemperatureCaliStatus[temperaturePoints, pressurePoints] = true;
                        SaveAndUpdConfigFile();
                        AutoCaliUpdCaliStatusToUI();
                    }

                    // 打开真空泵
                    if (!(await AutoCaliPumpClose()))
                    {
                        AlarmRLedOn();
                        AutoCaliPrintMsgAndLogMsg($"{msgID}. 真空泵关闭失败！");
                        CommandsBase.bHasCMDExecuting = false;
                        MessageBox.Show($"{msgID}. 真空泵关闭失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                        StopCaliTimeTimer();

                        return;
                    }
                    else
                    {
                        AutoCaliPrintMsgAndLogMsg($"{msgID}. 真空泵关闭成功！");
                    }
                }
                catch (Exception ex)
                {
                    AutoCaliPrintMsgAndLogMsg($"{args[1]}-[{temperatureWithSymbol[temperaturePoints]}]-[{pressureWithSymbol[errorPressure]}], error:{ex.Message}, 数据采集发生错误！");
                    CommandsBase.bHasCMDExecuting = false;

                    StopCaliTimeTimer();

                    return;
                }
            }

            CommandsBase.bHasCMDExecuting = false;
            StopCaliTimeTimer();

            await AutoCaliAlarmRGBOp(AutoCalibrationCMDsType.eAutoCMD_BatchBoard_LED_G_On);
            await AutoCaliPressureContrillerOutputClose();
            await AutoCaliTemperatureBoxStop();

            AutoCaliPrintMsgAndLogMsg("******************************* 温补完成 *******************************");
        }

        private async Task<bool> AutoCaliAlarmRGBOp(AutoCalibrationCMDsType rgbSel)
        {
            bool result = false;

            switch (rgbSel)
            {
                case AutoCalibrationCMDsType.eAutoCMD_BatchBoard_LED_R_Flashing:
                case AutoCalibrationCMDsType.eAutoCMD_BatchBoard_LED_G_Flashing:
                case AutoCalibrationCMDsType.eAutoCMD_BatchBoard_LED_B_Flashing:
                case AutoCalibrationCMDsType.eAutoCMD_BatchBoard_LED_R_On:
                case AutoCalibrationCMDsType.eAutoCMD_BatchBoard_LED_G_On:
                case AutoCalibrationCMDsType.eAutoCMD_BatchBoard_LED_R_Off:
                case AutoCalibrationCMDsType.eAutoCMD_BatchBoard_LED_G_Off:
                    break;

                default:
                    return false;
            }

            AutomaticCalibrationManager autoCalCmdManager = new AutomaticCalibrationManager(batchBoardSerialPort, rgbSel);

            result = await autoCalCmdManager.AutomaticCaliCMDsStart();

            return result;
        }

        private void AutoCaliPrintMsgAndLogMsg(string msg)
        {
            loggerDebugMsg(msg);
            SerialPortsBase.PrintMessage(msg);
        }

        private async Task<bool> AutoCaliPumpOpen()
        {
            bool result = false;
            AutomaticCalibrationManager autoCalCmdManager = new AutomaticCalibrationManager(batchBoardSerialPort, AutoCalibrationCMDsType.eAutoCMD_BatchBoard_Pump_Open);

            result = await autoCalCmdManager.AutomaticCaliCMDsStart();

            return result;
        }

        private async Task<bool> AutoCaliPumpClose()
        {
            bool result = false;
            AutomaticCalibrationManager autoCalCmdManager = new AutomaticCalibrationManager(batchBoardSerialPort, AutoCalibrationCMDsType.eAutoCMD_BatchBoard_Pump_Close);

            result = await autoCalCmdManager.AutomaticCaliCMDsStart();

            return result;
        }

        private async Task<bool> AutoCaliPressureControllerOutput()
        {
            bool result = false;
            AutomaticCalibrationManager autoCalCmdManager = new AutomaticCalibrationManager(preControllerSerialPort, AutoCalibrationCMDsType.eAutoCMD_PressureControl_Pressurization);

            result = await autoCalCmdManager.AutomaticCaliCMDsStart();

            return result;
        }

        private async Task<bool> AutoCaliPressureContrillerOutputClose()
        {
            bool result = false;
            AutomaticCalibrationManager autoCalCmdManager = new AutomaticCalibrationManager(preControllerSerialPort, AutoCalibrationCMDsType.eAutoCMD_PressureControl_PressureRelief);

            result = await autoCalCmdManager.AutomaticCaliCMDsStart();

            return result;
        }

        private async Task<bool> AutoCaliTemperatureBoxStart()
        {
            bool result = false;
            AutomaticCalibrationManager autoCalCmdManager = new AutomaticCalibrationManager(temperatureBoxSerialPort, AutoCalibrationCMDsType.eAutoCMD_TemperatureBoxStart);

            result = await autoCalCmdManager.AutomaticCaliCMDsStart();

            return result;
        }

        private async Task<bool> AutoCaliTemperatureBoxStop()
        {
            bool result = false;
            AutomaticCalibrationManager autoCalCmdManager = new AutomaticCalibrationManager(temperatureBoxSerialPort, AutoCalibrationCMDsType.eAutoCMD_TemperatureBoxStop);

            result = await autoCalCmdManager.AutomaticCaliCMDsStart();

            return result;
        }

        private async Task<bool> AutoCaliTemperatureBoxSetTemperature(string temperature)
        {
            bool result = false;
            AutomaticCalibrationManager autoCalCmdManager = new AutomaticCalibrationManager(temperatureBoxSerialPort, AutoCalibrationCMDsType.eAutoCMD_TemperatureBoxSetTemperature, new object[] { temperature });

            result = await autoCalCmdManager.AutomaticCaliCMDsStart();

            return result;
        }

        private async Task<bool> AutoCaliPressureControllerSetUnit(string unit)
        {
            bool result = false;
            AutomaticCalibrationManager autoCalCmdManager = new AutomaticCalibrationManager(preControllerSerialPort, AutoCalibrationCMDsType.eAutoCMD_PressureControl_SetUnit, new object[] { unit });

            result = await autoCalCmdManager.AutomaticCaliCMDsStart();

            return result;
        }

        private async Task<bool> AutoCaliPressureControllerCheckUnit()
        {
            bool result = false;
            AutomaticCalibrationManager autoCalCmdManager = new AutomaticCalibrationManager(preControllerSerialPort, AutoCalibrationCMDsType.eAutoCMD_PressureControl_QueryUnit);

            result = await autoCalCmdManager.AutomaticCaliCMDsStart();

            return result;
        }

        private (bool, string) AutoCaliSaveCollectionData(string temperature, string pressure, string route)
        {
            string currentTemperature = temperature;
            string currentPressure = pressure;

            string searchPattern = "^.*-\\[" + currentTemperature + "\\]-\\[" + currentPressure + "\\].json$";

            string SNFileDir = Path.Combine(_exePath, "result", JsonConfigInfo.configInfo.OrderSerialNumber);
            string TemperatureFileDir = Path.Combine(SNFileDir, currentTemperature);

            string targetFilePath = null;
            bool bIsFileExist = false;

            JsonDevsInfo info = null;

            try
            {
                if (!Directory.Exists(SNFileDir))
                {
                    Directory.CreateDirectory(SNFileDir);
                }
            }
            catch (Exception ex)
            {
                SerialPortsBase.PrintMessage(ex.Message);
                MessageBox.Show($"创建{SNFileDir}文件夹失败: " + ex.Message, "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                return (false, null);
            }

            try
            {
                if (!Directory.Exists(TemperatureFileDir))
                {
                    Directory.CreateDirectory(TemperatureFileDir);
                }
                else
                {
                    string[] files = Directory.GetFiles(TemperatureFileDir);
                    string searchFileName = null;

                    foreach (string file in files)
                    {
                        searchFileName = Path.GetFileName(file);

                        if (Regex.IsMatch(searchFileName, searchPattern))
                        {
                            bIsFileExist = true;
                            targetFilePath = file;
                        }
                    }
                }

                if (bIsFileExist)
                {
                    string jsonFileString = File.ReadAllText(targetFilePath);

                    info = JsonConvert.DeserializeObject<JsonDevsInfo>(jsonFileString);
                }
                else
                {
                    string fileName = $"{DateTime.Now:yyyMMdd_HHmm}-[{currentTemperature}]-[{currentPressure}].json";

                    targetFilePath = Path.Combine(TemperatureFileDir, fileName);

                    info = new JsonDevsInfo()
                    {
                        OrderSerialNumber = JsonConfigInfo.configInfo.OrderSerialNumber,
                        TemperaturePoint = currentTemperature,
                        RangeUp = JsonConfigInfo.configInfo.RangeUp,
                        RangeDown = JsonConfigInfo.configInfo.RangeDown,
                        EqualPoints = JsonConfigInfo.configInfo.EqualVal,
                        CurrentPressure = currentPressure,
                    };
                }
            }
            catch (Exception ex)
            {
                SerialPortsBase.PrintMessage(ex.Message);
                MessageBox.Show(ex.Message, "保存失败", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                return (false, null);
            }

            for (int i = 0; i < 32; i++)
            {
                if (gCheckBoxDevsSelectedAry[i].Checked)
                {
                    AutoCaliUpdCollectionDataToJsonFile(ref info, i + 1, route);
                }
            }

            var settings = new JsonSerializerSettings
            {
                Formatting = Formatting.Indented,
                NullValueHandling = NullValueHandling.Include,
            };

            var jsonString = JsonConvert.SerializeObject(info, settings);

            File.WriteAllText(targetFilePath, jsonString);

            SerialPortsBase.PrintMessage($"{targetFilePath}更新数据成功!");

            return (true, targetFilePath);
        }

        private void AutoCaliUpdCollectionDataToJsonFile(ref JsonDevsInfo info, int chl, string route)
        {
            int itemIdx = (chl - 1) * 10;

            if (route == "上行程")
            {
                info.dataInfo[chl - 1].Data["压力(上行)"][0] = listViewSrcData.Items[itemIdx + 0].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][1] = listViewSrcData.Items[itemIdx + 1].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][2] = listViewSrcData.Items[itemIdx + 2].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][3] = listViewSrcData.Items[itemIdx + 3].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][4] = listViewSrcData.Items[itemIdx + 4].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][5] = listViewSrcData.Items[itemIdx + 5].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][6] = listViewSrcData.Items[itemIdx + 6].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][7] = listViewSrcData.Items[itemIdx + 7].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][8] = listViewSrcData.Items[itemIdx + 8].SubItems[1].Text;
                info.dataInfo[chl - 1].Data["压力(上行)"][9] = listViewSrcData.Items[itemIdx + 9].SubItems[1].Text;

                info.dataInfo[chl - 1].Data["温度(上行)"][0] = listViewSrcData.Items[itemIdx + 0].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][1] = listViewSrcData.Items[itemIdx + 1].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][2] = listViewSrcData.Items[itemIdx + 2].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][3] = listViewSrcData.Items[itemIdx + 3].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][4] = listViewSrcData.Items[itemIdx + 4].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][5] = listViewSrcData.Items[itemIdx + 5].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][6] = listViewSrcData.Items[itemIdx + 6].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][7] = listViewSrcData.Items[itemIdx + 7].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][8] = listViewSrcData.Items[itemIdx + 8].SubItems[2].Text;
                info.dataInfo[chl - 1].Data["温度(上行)"][9] = listViewSrcData.Items[itemIdx + 9].SubItems[2].Text;
            }
            else // "下行程"
            {
                info.dataInfo[chl - 1].Data["压力(下行)"][0] = listViewSrcData.Items[itemIdx + 0].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][1] = listViewSrcData.Items[itemIdx + 1].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][2] = listViewSrcData.Items[itemIdx + 2].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][3] = listViewSrcData.Items[itemIdx + 3].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][4] = listViewSrcData.Items[itemIdx + 4].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][5] = listViewSrcData.Items[itemIdx + 5].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][6] = listViewSrcData.Items[itemIdx + 6].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][7] = listViewSrcData.Items[itemIdx + 7].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][8] = listViewSrcData.Items[itemIdx + 8].SubItems[3].Text;
                info.dataInfo[chl - 1].Data["压力(下行)"][9] = listViewSrcData.Items[itemIdx + 9].SubItems[3].Text;

                info.dataInfo[chl - 1].Data["温度(下行)"][0] = listViewSrcData.Items[itemIdx + 0].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][1] = listViewSrcData.Items[itemIdx + 1].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][2] = listViewSrcData.Items[itemIdx + 2].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][3] = listViewSrcData.Items[itemIdx + 3].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][4] = listViewSrcData.Items[itemIdx + 4].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][5] = listViewSrcData.Items[itemIdx + 5].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][6] = listViewSrcData.Items[itemIdx + 6].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][7] = listViewSrcData.Items[itemIdx + 7].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][8] = listViewSrcData.Items[itemIdx + 8].SubItems[4].Text;
                info.dataInfo[chl - 1].Data["温度(下行)"][9] = listViewSrcData.Items[itemIdx + 9].SubItems[4].Text;
            }
        }

        private async Task<bool> AutoCaliCheckCurrentPressure(string targetPressure, string errPerOfRge)
        {
            object[] args = new object[2];
            bool result = true;

            if (errPerOfRge == "0.01%")
            {
                args[0] = (JsonConfigInfo.configInfo.RangeUp - JsonConfigInfo.configInfo.RangeDown) * 0.0001;
            }
            else if (errPerOfRge == "0.02%")
            {
                args[0] = (JsonConfigInfo.configInfo.RangeUp - JsonConfigInfo.configInfo.RangeDown) * 0.0002;
            }
            else if (errPerOfRge == "0.03%")
            {
                args[0] = (JsonConfigInfo.configInfo.RangeUp - JsonConfigInfo.configInfo.RangeDown) * 0.0003;
            }
            else if (errPerOfRge == "0.04%")
            {
                args[0] = (JsonConfigInfo.configInfo.RangeUp - JsonConfigInfo.configInfo.RangeDown) * 0.0004;
            }
            else if (errPerOfRge == "0.05%")
            {
                args[0] = (JsonConfigInfo.configInfo.RangeUp - JsonConfigInfo.configInfo.RangeDown) * 0.0005;
            }
            else if (errPerOfRge == "0.06%")
            {
                args[0] = (JsonConfigInfo.configInfo.RangeUp - JsonConfigInfo.configInfo.RangeDown) * 0.0006;
            }
            else if (errPerOfRge == "0.07%")
            {
                args[0] = (JsonConfigInfo.configInfo.RangeUp - JsonConfigInfo.configInfo.RangeDown) * 0.0007;
            }
            else if (errPerOfRge == "0.08%")
            {
                args[0] = (JsonConfigInfo.configInfo.RangeUp - JsonConfigInfo.configInfo.RangeDown) * 0.0008;
            }
            else if (errPerOfRge == "0.09%")
            {
                args[0] = (JsonConfigInfo.configInfo.RangeUp - JsonConfigInfo.configInfo.RangeDown) * 0.0009;
            }
            else if (errPerOfRge == "0.1%")
            {
                args[0] = (JsonConfigInfo.configInfo.RangeUp - JsonConfigInfo.configInfo.RangeDown) * 0.001;
            }
            else
            {
                args[0] = (JsonConfigInfo.configInfo.RangeUp - JsonConfigInfo.configInfo.RangeDown) * 0.0001;
            }

            args[1] = targetPressure;

            AutomaticCalibrationManager autoCalCmdManager = new AutomaticCalibrationManager(preControllerSerialPort, AutoCalibrationCMDsType.eAutoCMD_PressureControl_QueryPressure, args);

            // 读10次，间隔4s
            for (int i = 0; i < 10; i++)
            {
                result = await autoCalCmdManager.AutomaticCaliCMDsStart();
                if (result)
                {
                    SerialPortsBase.PrintMessage($"第{i + 1}次检查实际压力(误差<{errPerOfRge})， 压力稳定！");
                }
                else
                {
                    SerialPortsBase.PrintMessage($"第{i + 1}次检查实际压力(误差>{errPerOfRge})， 压力不稳定！");

                    return false;
                }

                await Task.Delay(TimeSpan.FromSeconds(2));
            }

            return true;
        }

        private async Task<bool> AutoCaliGetFitDataInfo(object[] args, int dataID)
        {
            bool result = false;
            AutomaticCalibrationManager autoCalCmdManager = new AutomaticCalibrationManager(hARTSerialPort_woyatechModem, AutoCalibrationCMDsType.eAutoCMD_HART_GetFitData, args);

            result = await autoCalCmdManager.AutomaticCaliCMDsStart();

            return result;
        }

        private async Task<bool> AutoCaliSwitchChannal(CMDsChlID chl)
        {
            bool result = false;
            AutomaticCalibrationManager autoCalCmdManager = new AutomaticCalibrationManager(batchBoardSerialPort, AutoCalibrationCMDsType.eAutoCMD_HART_SwitchChannel, new object[] { chl });

            result = await autoCalCmdManager.AutomaticCaliCMDsStart();

            return result;
        }

        private async Task<bool> AutoCaliPressureControllerSetPressure(string pressure)
        {
            bool result = false;
            AutomaticCalibrationManager autoCalCmdManager = new AutomaticCalibrationManager(preControllerSerialPort, AutoCalibrationCMDsType.eAutoCMD_PressureControl_SetPressure, new object[] { pressure });

            result = await autoCalCmdManager.AutomaticCaliCMDsStart();

            return result;
        }

        private bool AutoCaliCheckAllSerialPorts()
        {
            if (!CheckTemperatureBoxSerialPortsWithLedAlarm())
            {
                loggerDebugMsg("温箱串口未打开！");
                return false;
            }

            if (!CheckBatchBoardSerialPortsWithLedAlarm())
            {
                loggerDebugMsg("批量调试箱串口未打开！");
                return false;
            }

            if (!CheckHARTSerialPortsWithLedAlarm())
            {
                loggerDebugMsg("HART串口未打开！");
                return false;
            }
                
            if(!CheckPressureControllerSerialPortsWithLedAlarm())
            {
                loggerDebugMsg("压力控制器串口未打开！");
                return false;
            }

            return true;
        }

        private bool CheckTemperatureBoxSerialPortsWithLedAlarm()
        {
            if (!temperatureBoxSerialPort.SerialPortIsOpen())
            {
                AlarmRLedOn();
                MessageBox.Show("温箱串口未打开！", "警告", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Warning);
                return false;
            }

            return true;
        }

        private bool CheckBatchBoardSerialPortsWithLedAlarm()
        {
            if (!batchBoardSerialPort.SerialPortIsOpen())
            {
                AlarmRLedOn();
                MessageBox.Show("标定调试箱串口未打开！", "警告", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Warning);
                return false;
            }

            return true;
        }

        private bool CheckHARTSerialPortsWithLedAlarm()
        {
            if (!hARTSerialPort_woyatechModem.SerialPortIsOpen())
            {
                AlarmRLedOn();
                MessageBox.Show("HART串口未打开！", "警告", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Warning);
                return false;
            }

            return true;
        }

        private bool CheckPressureControllerSerialPortsWithLedAlarm()
        { 
            if (!preControllerSerialPort.SerialPortIsOpen())
            {
                AlarmRLedOn();
                MessageBox.Show("压力控制器串口未打开！", "警告", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Warning);
                return false;
            }

            return true;
        }

        private void SaveAndUpdConfigFile()
        {
            try
            {
                string fileName = $"{JsonConfigInfo.configInfo.OrderSerialNumber}_Config.json";
                string fileDirPath = Path.Combine(_exePath, "result", txtBoxConfigSN.Text);

                // 检查文件夹是否存在，如果不存在则创建它
                if (!Directory.Exists(fileDirPath))
                {
                    Directory.CreateDirectory(fileDirPath);
                }

                string filePath = Path.Combine(fileDirPath, fileName);

                var settings = new JsonSerializerSettings
                {
                    Formatting = Formatting.Indented,
                    NullValueHandling = NullValueHandling.Include,
                };

                var jsonString = JsonConvert.SerializeObject(JsonConfigInfo.configInfo, settings);

                File.WriteAllText(filePath, jsonString);
            }
            catch (Exception ex)
            {
                SerialPortsBase.PrintMessage("SaveAndUpdConfigFile() 失败！" + ex.Message);
            }
        }

        private void AutoCaliUpdCaliStatusToUI()
        {
            Button[,] btnAutoCaliStatusCtls = new Button[6, 9]
            {
                { btnAutoStatusIndictor11, btnAutoStatusIndictor12, btnAutoStatusIndictor13, btnAutoStatusIndictor14, btnAutoStatusIndictor15, btnAutoStatusIndictor16, btnAutoStatusIndictor17, btnAutoStatusIndictor18, btnAutoStatusIndictor19},
                { btnAutoStatusIndictor21, btnAutoStatusIndictor22, btnAutoStatusIndictor23, btnAutoStatusIndictor24, btnAutoStatusIndictor25, btnAutoStatusIndictor26, btnAutoStatusIndictor27, btnAutoStatusIndictor28, btnAutoStatusIndictor29},
                { btnAutoStatusIndictor31, btnAutoStatusIndictor32, btnAutoStatusIndictor33, btnAutoStatusIndictor34, btnAutoStatusIndictor35, btnAutoStatusIndictor36, btnAutoStatusIndictor37, btnAutoStatusIndictor38, btnAutoStatusIndictor39},
                { btnAutoStatusIndictor41, btnAutoStatusIndictor42, btnAutoStatusIndictor43, btnAutoStatusIndictor44, btnAutoStatusIndictor45, btnAutoStatusIndictor46, btnAutoStatusIndictor47, btnAutoStatusIndictor48, btnAutoStatusIndictor49},
                { btnAutoStatusIndictor51, btnAutoStatusIndictor52, btnAutoStatusIndictor53, btnAutoStatusIndictor54, btnAutoStatusIndictor55, btnAutoStatusIndictor56, btnAutoStatusIndictor57, btnAutoStatusIndictor58, btnAutoStatusIndictor59},
                { btnAutoStatusIndictor61, btnAutoStatusIndictor62, btnAutoStatusIndictor63, btnAutoStatusIndictor64, btnAutoStatusIndictor65, btnAutoStatusIndictor66, btnAutoStatusIndictor67, btnAutoStatusIndictor68, btnAutoStatusIndictor69},
            };

            for (int i = 0; i < 6; i++)
            {
                for (int j = 0; j < 9; j++)
                {
                    if (JsonConfigInfo.configInfo.TemperatureCaliStatus[i, j] == true)
                    {
                        btnAutoCaliStatusCtls[i, j].BackColor = Color.IndianRed;
                    }
                    else
                    {
                        btnAutoCaliStatusCtls[i, j].BackColor = Color.DarkGray;
                    }
                }
            }
        }

        private bool GetTemperatureCaliStatus(int temperatureID)
        {
            for (int i = 0; i < 9; i++)
            {
                if (JsonConfigInfo.configInfo.TemperatureCaliStatus[temperatureID, i] == false)
                {
                    return false;
                }
            }

            return true;
        }

        private async void AlarmRLedOn()
        {
            try
            {
                BatchCaliBoardCMDsSwitchRGB batchBoardSwitchRGB = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Switch R Flash", RGBSel.eRGB_R_Flashing);
                await batchBoardSwitchRGB.ExecuteCMD();
            }
            catch (Exception ex)
            { 
            
            }
        }

        private async void AlarmRLedOff()
        {
            try
            {
                BatchCaliBoardCMDsSwitchRGB batchBoardSwitchRGB = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Switch R Flash", RGBSel.eRGB_G_ON);
                await batchBoardSwitchRGB.ExecuteCMD();
            }
            catch (Exception ex)
            {

            }
        }

        public static void loggerDebugMsg(string msg)
        {
            if (_logger.GetLogFileDir() == null)
            {
                return;
            }

            _logger.Log(msg);
        }

        private int GetTimeInSeconds()
        {
            string timeSel = cboxKeepingTime.Text;
            int timeInSeconds = 0;

            if (timeSel == "1h")
            {
                timeInSeconds = 1 * 60 * 60;
            }
            else if (timeSel == "1.5h")
            {
                timeInSeconds = (int)(1.5 * 60 * 60);
            }
            else if (timeSel == "2h")
            {
                timeInSeconds = (int)(2 * 60 * 60);
            }
            else if (timeSel == "2.5h")
            {
                timeInSeconds = (int)(2.5 * 60 * 60);
            }
            else if (timeSel == "3h")
            {
                timeInSeconds = (int)(3 * 60 * 60);
            }
            else // TEST
            {
                timeInSeconds = 20;
            }

            return timeInSeconds;
        }

        private void CountDownTimer_Tick(object sender, EventArgs e)
        {
            if (remainingTimeInSeconds > 0)
            {
                remainingTimeInSeconds--;
                UpdateTimeDisplay(remainingTimeInSeconds);
            }
            else if (remainingTimeInSeconds == 0)
            {
                UpdateTimeDisplay(remainingTimeInSeconds);
            }
        }

        private void UpdateTimeDisplay(int timeInSeconds)
        {
            int hours = timeInSeconds / 3600;
            int minutes = (timeInSeconds % 3600) / 60;
            int seconds = timeInSeconds % 60;

            string timeString = string.Format("{0:D2}:{1:D2}:{2:D2}", hours, minutes, seconds);

            labelRemainTime.Text = timeString;
        }

        private void cboxKeepingTime_SelectedIndexChanged(object sender, EventArgs e)
        {
            string selectedItem = cboxKeepingTime.SelectedItem.ToString();
            int timeInSeconds = 0;

            if (CommandsBase.bHasCMDExecuting == false)
            {
                timeInSeconds = GetTimeInSeconds();
                UpdateTimeDisplay(timeInSeconds);
            }
        }

        private void CaliTotalTimer_Tick(object sender, EventArgs e)
        {
            caliTimeInSeconds++;
            UpdateCaliTotalTime(caliTimeInSeconds);
        }

        private void UpdateCaliTotalTime(int timeInSeconds)
        {
            // 计算天、时、分、秒
            int days = timeInSeconds / (24 * 3600);  // 计算天数
            int hours = (timeInSeconds % (24 * 3600)) / 3600;  // 计算小时数
            int minutes = (timeInSeconds % 3600) / 60;  // 计算分钟数
            int seconds = timeInSeconds % 60;  // 计算秒数

            labelCaliTotalTime.Text = string.Format("{0:D2}:{1:D2}:{2:D2}:{3:D2}", days, hours, minutes, seconds);
        }

        private void StartCaliTimeTimer()
        {
            caliTimeInSeconds = 0;
            UpdateCaliTotalTime(caliTimeInSeconds);
            caliTotalTimer.Start();
        }

        private void StopCaliTimeTimer()
        {
            caliTimeInSeconds = 0;
            caliTotalTimer.Stop();
        }

        private async void btnPumpOpen_Click(object sender, EventArgs e)
        {
            BatchCaliBoardCMDsSwitchRGB batchBoardSwitch = null;

            if (!batchBoardSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("调试箱串口未打开。");
                return;
            }

            try
            {
                batchBoardSwitch = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Turn on the vacuum pump", RGBSel.eVacuum_Pump_ON);

                await batchBoardSwitch.ExecuteCMD();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"真空泵控制串口错误: {ex.Message}", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
        }

        private async void btnPumpClose_Click(object sender, EventArgs e)
        {
            BatchCaliBoardCMDsSwitchRGB batchBoardSwitch = null;

            if (!batchBoardSerialPort.SerialPortIsOpen())
            {
                PrintfMsg("调试箱串口未打开。");
                return;
            }

            try
            {
                batchBoardSwitch = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Turn off the vacuum pump", RGBSel.eVacuum_Pump_OFF);

                await batchBoardSwitch.ExecuteCMD();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"真空泵控制串口错误: {ex.Message}", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);
            }
        }

        private void btnAnalogData_Click(object sender, EventArgs e)
        {
            //string[] startCells = new string[32]
            //{ 
            //    "A1", "D1", "G1", "J1", "M1", "P1", "S1", "V1",
            //    "AA1", "AD1", "AG1", "AJ1", "AM1", "AP1", "AS1", "AV1",
            //    "BA1", "BD1", "BG1", "BJ1", "BM1", "BP1", "BS1", "BV1",
            //    "CA1", "CD1", "CG1", "CJ1", "CM1", "CP1", "CS1", "CV1",
            //};

            string excelFilePath = Path.Combine(_exePath, "result", txtBoxConfigSN.Text, "Retest.xlsx");
            string PVStartCell = "C1";
            string mAStartCell = "D1";

            FileInfo fileInfo = new FileInfo(excelFilePath);

            if (!fileInfo.Exists)
            {
                MessageBox.Show("复测结果Excel文件不存在");
                return;
            }

            try
            {
                ExcelPackage.LicenseContext = LicenseContext.NonCommercial;

                using (var package = new ExcelPackage(fileInfo))
                {
                    for (int i = 0; i < 32; i++)
                    {
                        if (gCheckBoxDevsSelectedAry[i].Checked)
                        {
                            var worksheet = package.Workbook.Worksheets[i];

                            var PVStartRange = worksheet.Cells[PVStartCell];
                            var mAStartRange = worksheet.Cells[mAStartCell];

                            int PVStartRow = PVStartRange.Start.Row;
                            int PVStartColumn = PVStartRange.Start.Column;

                            var PVData = new List<string>();

                            int row = PVStartRow;
                            // PV
                            while (true)
                            {
                                var cellValue = worksheet.Cells[row, PVStartColumn].Text;

                                if (string.IsNullOrWhiteSpace(cellValue))
                                {
                                    break;
                                }

                                PVData.Add(cellValue);
                                row++;
                            }

                            // calc result
                            List<double> PVResult = PVData.ConvertAll(s => Convert.ToDouble(s));

                            (double max, int maxIndex, double min, int minIndex) result = FindMinMaxWithIndex(PVResult);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                
            }

            if ((retestUI == null) || retestUI.IsDisposed)
            {
                retestUI = new RetestUI();
            }

            retestUI.Show();

        }

        public (double max, int maxIndex, double min, int minIndex) FindMinMaxWithIndex(List<double> numbers)
        {
            if (numbers == null || numbers.Count == 0)
            {
                throw new ArgumentException("List is empty");
            }

            double max = numbers[0];
            int maxIndex = 0;
            double min = numbers[0];
            int minIndex = 0;

            for (int i = 0; i < numbers.Count; i++)
            {
                if (numbers[i] > max)
                {
                    max = numbers[i];
                    maxIndex = i;
                }
                else if (numbers[i] < min)
                {
                    min = numbers[i];
                    minIndex = i;
                }
            }

            return (max, maxIndex, min, minIndex);
        }

        private void SaveCollectionDataToExcel(ref ExcelHelper excelHelper)
        { 
            string filePath = Path.Combine(_exePath, "result", txtBoxConfigSN.Text, "Retest.xlsx");

            for (int i = 0; i < 32; i++)
            {
                if (gCheckBoxDevsSelectedAry[i].Checked)
                {
                    excelHelper.SaveDataToExcel(filePath, i, $"变送器{i + 1}", "A1", excelHelper.retestData[i]);
                }
            }

            //excelHelper.ClrRetestDataBuffer();
        }

        private void UpdExcelTitle()
        {
            //for (int i = 0; i < 32; i++)
            //{
            //    excelHelperCls.retestData[i].Add(new List<string> { $"SN: {JsonConfigInfo.configInfo.transducersInfo[i].SN}" });
            //    excelHelperCls.retestData[i].Add(new List<string> { $"LongAddress: {JsonConfigInfo.configInfo.transducersInfo[i].LongAddress}" });
            //    excelHelperCls.retestData[i].Add(new List<string> { "No.", "时间", "主变量", "电流值(mA)", "温度(℃)" });
            //}
        }

        private async void btnRetStart_Click(object sender, EventArgs e)
        {
            TextBox[] textBoxes = new TextBox[32]
            {
                txtBoxRetestTrans1, txtBoxRetestTrans2, txtBoxRetestTrans3, txtBoxRetestTrans4, txtBoxRetestTrans5,
                txtBoxRetestTrans6, txtBoxRetestTrans7, txtBoxRetestTrans8, txtBoxRetestTrans9, txtBoxRetestTrans10,
                txtBoxRetestTrans11, txtBoxRetestTrans12, txtBoxRetestTrans13, txtBoxRetestTrans14, txtBoxRetestTrans15,
                txtBoxRetestTrans16, txtBoxRetestTrans17, txtBoxRetestTrans18, txtBoxRetestTrans19, txtBoxRetestTrans20,
                txtBoxRetestTrans21, txtBoxRetestTrans22, txtBoxRetestTrans23, txtBoxRetestTrans24, txtBoxRetestTrans25,
                txtBoxRetestTrans26, txtBoxRetestTrans27, txtBoxRetestTrans28, txtBoxRetestTrans29, txtBoxRetestTrans30,
                txtBoxRetestTrans31, txtBoxRetestTrans32
            };

            CMDsChlID[] cMDsChlIDs = new CMDsChlID[32]
            {
                CMDsChlID.eChannel1, CMDsChlID.eChannel2, CMDsChlID.eChannel3, CMDsChlID.eChannel4, CMDsChlID.eChannel5, CMDsChlID.eChannel6, CMDsChlID.eChannel7, CMDsChlID.eChannel8,
                CMDsChlID.eChannel9, CMDsChlID.eChannel10, CMDsChlID.eChannel11, CMDsChlID.eChannel12, CMDsChlID.eChannel13, CMDsChlID.eChannel14, CMDsChlID.eChannel15, CMDsChlID.eChannel16,
                CMDsChlID.eChannel17, CMDsChlID.eChannel18, CMDsChlID.eChannel19, CMDsChlID.eChannel20, CMDsChlID.eChannel21, CMDsChlID.eChannel22, CMDsChlID.eChannel23, CMDsChlID.eChannel24,
                CMDsChlID.eChannel25, CMDsChlID.eChannel26, CMDsChlID.eChannel27, CMDsChlID.eChannel28, CMDsChlID.eChannel29, CMDsChlID.eChannel30, CMDsChlID.eChannel31, CMDsChlID.eChannel32,
            };

            TextBox[] showPVTxtBox = new TextBox[32]
            {
                txtBoxPVTrans1, txtBoxPVTrans2, txtBoxPVTrans3, txtBoxPVTrans4, txtBoxPVTrans5, txtBoxPVTrans6,
                txtBoxPVTrans7, txtBoxPVTrans8, txtBoxPVTrans9, txtBoxPVTrans10, txtBoxPVTrans11, txtBoxPVTrans12,
                txtBoxPVTrans13, txtBoxPVTrans14, txtBoxPVTrans15, txtBoxPVTrans16, txtBoxPVTrans17, txtBoxPVTrans18,
                txtBoxPVTrans19, txtBoxPVTrans20, txtBoxPVTrans21, txtBoxPVTrans22, txtBoxPVTrans23, txtBoxPVTrans24,
                txtBoxPVTrans25, txtBoxPVTrans26, txtBoxPVTrans27, txtBoxPVTrans28, txtBoxPVTrans29, txtBoxPVTrans30,
                txtBoxPVTrans31, txtBoxPVTrans32
            };

            TextBox[] showCurrentTxtBox = new TextBox[32]
            {
                txtShowCurrent1, txtShowCurrent2, txtShowCurrent3, txtShowCurrent4, txtShowCurrent5, txtShowCurrent6,
                txtShowCurrent7, txtShowCurrent8, txtShowCurrent9, txtShowCurrent10, txtShowCurrent11, txtShowCurrent12,
                txtShowCurrent13, txtShowCurrent14, txtShowCurrent15, txtShowCurrent16, txtShowCurrent17, txtShowCurrent18,
                txtShowCurrent19, txtShowCurrent20, txtShowCurrent21, txtShowCurrent22, txtShowCurrent23, txtShowCurrent24,
                txtShowCurrent25, txtShowCurrent26, txtShowCurrent27, txtShowCurrent28, txtShowCurrent29, txtShowCurrent30,
                txtShowCurrent31, txtShowCurrent32
            };

            string[] pressure = new string[9]
            {
                txtBoxRetestPre1.Text.TrimEnd('k','P','a'),
                txtBoxRetestPre2.Text.TrimEnd('k','P','a'),
                txtBoxRetestPre3.Text.TrimEnd('k','P','a'),
                txtBoxRetestPre4.Text.TrimEnd('k','P','a'),
                txtBoxRetestPre5.Text.TrimEnd('k','P','a'),
                txtBoxRetestPre6.Text.TrimEnd('k','P','a'),
                txtBoxRetestPre7.Text.TrimEnd('k','P','a'),
                txtBoxRetestPre8.Text.TrimEnd('k','P','a'),
                txtBoxRetestPre9.Text.TrimEnd('k','P','a'),
            };

            int staPressureTime = GetStablizationPressureTimeSeconds();

            bool result = false;
            AutomaticCalibrationManager retestCmdHART1ReadPV = new AutomaticCalibrationManager(hARTSerialPort_woyatechModem, AutoCalibrationCMDsType.eRetest_HART1ReadPV);
            AutomaticCalibrationManager retestCmdHART2ReadLoopCurent = new AutomaticCalibrationManager(hARTSerialPort_woyatechModem, AutoCalibrationCMDsType.eRetest_HART2ReadLoopCurrent);

            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #1 Read PV"], new TextBoxRetestUpdater(textBoxes));
            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #1 Show PV"], new TextBoxShowPVUpdater(showPVTxtBox));

            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #2 Read Current"], new TextBoxRetestUpdater(textBoxes));
            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #2 Show Current"], new TextBoxShowPVUpdater(showCurrentTxtBox));

            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #1 Read PV Excel"], new RetestAnalyzeExcelUpdater(ref excelHelperCls));
            hARTSerialPort_woyatechModem.RegisterObservers(HARTObserversInfo.info["HART #2 Read Current Excel"], new RetestAnalyzeExcelUpdater(ref excelHelperCls));

            try
            {
                //打开真空泵
                if (!(await AutoCaliPumpOpen()))
                {
                    AlarmRLedOn();
                    MessageBox.Show($"真空泵打开失败！", "错误", buttons: MessageBoxButtons.OK, icon: MessageBoxIcon.Error);

                    return;
                }
                else
                {
                    SerialPortsBase.PrintMessage("真空泵打开成功！");
                }
                await Task.Delay(TimeSpan.FromSeconds(2));

                // 压力控制输出
                if (!(await AutoCaliPressureControllerOutput()))
                {
                    AlarmRLedOn();
                    SerialPortsBase.PrintMessage("压力控制器输出 设置失败！");

                    return;
                }
                else
                {
                    SerialPortsBase.PrintMessage("压力控制器输出 设置成功！");
                }
                await Task.Delay(TimeSpan.FromSeconds(2));

                InitExcel();

                // 上行程
                RetestHART1ReadPV.upOrDown = "Up";
                RetestHART2ReadLoopCurrent.upOrDown = "Up";
                for (int i = 0; i < 9; i++)
                {
                    // 设置压力
                    if (!(await AutoCaliPressureControllerSetPressure(pressure[i])))
                    {
                        AlarmRLedOn();
                        SerialPortsBase.PrintMessage($"压力{pressure[i]}kPa 设置失败！");

                        return;
                    }
                    else
                    {
                        SerialPortsBase.PrintMessage($"压力{pressure[i]}kPa 设置成功！");
                    }
                    SerialPortsBase.PrintMessage("******************** 等待中 ********************");
                    await Task.Delay(TimeSpan.FromSeconds(staPressureTime));

                    for (int chl = 0; chl < 32; chl++)
                    {
                        if (gCheckBoxDevsSelectedAry[chl].Checked)
                        {
                            if (await AutoCaliSwitchChannal(cMDsChlIDs[chl]))
                            {
                                result = await retestCmdHART1ReadPV.AutomaticCaliCMDsStart();
                                result = await retestCmdHART2ReadLoopCurent.AutomaticCaliCMDsStart();
                                await Task.Delay(TimeSpan.FromSeconds(0.5));
                            }
                        }
                    }
                    await Task.Delay(TimeSpan.FromSeconds(2));
                }

                await Task.Delay(TimeSpan.FromSeconds(1));
                for (int chl = 0; chl < 32; chl++)
                {
                    if (gCheckBoxDevsSelectedAry[chl].Checked)
                    {
                        excelHelperCls.AddColumnDataFromCell(_excelFilePath, "数据", 3, 1 + chl * 7, excelHelperCls.upRetestPVData[chl]);
                        excelHelperCls.AddColumnDataFromCell(_excelFilePath, "数据", 3, 2 + chl * 7, excelHelperCls.upRetestCurrentData[chl]);
                    }
                }

                // 下行程
                RetestHART1ReadPV.upOrDown = "Down";
                RetestHART2ReadLoopCurrent.upOrDown = "Down";
                for (int i = 0; i < 9; i++)
                {
                    // 设置压力
                    if (!(await AutoCaliPressureControllerSetPressure(pressure[8 - i])))
                    {
                        AlarmRLedOn();
                        SerialPortsBase.PrintMessage($"压力{pressure[8 - i]}kPa 设置失败！");

                        return;
                    }
                    else
                    {
                        SerialPortsBase.PrintMessage($"压力{pressure[8 - i]}kPa 设置成功！");
                    }
                    SerialPortsBase.PrintMessage("******************** 等待中 ********************");
                    await Task.Delay(TimeSpan.FromSeconds(staPressureTime));

                    for (int chl = 0; chl < 32; chl++)
                    {
                        if (gCheckBoxDevsSelectedAry[chl].Checked)
                        {
                            if (await AutoCaliSwitchChannal(cMDsChlIDs[chl]))
                            {
                                result = await retestCmdHART1ReadPV.AutomaticCaliCMDsStart();
                                result = await retestCmdHART2ReadLoopCurent.AutomaticCaliCMDsStart();
                                await Task.Delay(TimeSpan.FromSeconds(0.5));
                            }
                        }
                    }
                    await Task.Delay(TimeSpan.FromSeconds(2));
                }

                await Task.Delay(TimeSpan.FromSeconds(1));
                for (int chl = 0; chl < 32; chl++)
                {
                    if (gCheckBoxDevsSelectedAry[chl].Checked)
                    {
                        excelHelperCls.AddColumnDataFromCellUpward(_excelFilePath, "数据", 12, 3 + chl * 7, excelHelperCls.downRetestPVData[chl]);
                        excelHelperCls.AddColumnDataFromCellUpward(_excelFilePath, "数据", 12, 4 + chl * 7, excelHelperCls.downRetestCurrentData[chl]);
                    }
                }

                // 计算回差、误差
                for (int chl = 0; chl < 32; chl++)
                {
                    if (gCheckBoxDevsSelectedAry[chl].Checked)
                    {
                        int row = 0;
                        int column = 0;

                        List<string> upDataString = new List<string>();
                        List<string> downDataString = new List<string>();

                        List<double> upDataDouble = new List<double>();
                        List<double> downDataDouble = new List<double>();

                        List<string> result1 = new List<string>();
                        List<string> result2 = new List<string>();

                        if (chl <= 7)
                        {
                            row = 3;
                        }
                        else if (chl <= 15)
                        {
                            row = 16;
                        }
                        else if (chl <= 23)
                        {
                            row = 29;
                        }
                        else if (chl <= 31)
                        {
                            row = 42;
                        }
                        else
                        {
                            return;
                        }

                        column = (chl % 8) * 7 + 1;

                        upDataString = excelHelperCls.ReadColumnsUntilEmpty(_excelFilePath, "数据", row, column);
                        downDataString = excelHelperCls.ReadColumnsUntilEmpty(_excelFilePath, "数据", row, column + 2);

                        double res = 0.0;

                        foreach (string dataStr in upDataString)
                        {
                            if (double.TryParse(dataStr, out res))
                            {
                                upDataDouble.Add(res);
                            }
                            else
                            {
                                return;
                            }
                        }

                        foreach (string dataStr in downDataString)
                        {
                            if (double.TryParse(dataStr, out res))
                            {
                                downDataDouble.Add(res);
                            }
                            else
                            {
                                return;
                            }
                        }

                        for (int i = 0; i < 9; i++)
                        {
                            result1.Add((upDataDouble[i] - downDataDouble[i]).ToString("F4"));
                            result2.Add(((upDataDouble[i] - downDataDouble[i]) / (JsonConfigInfo.configInfo.RangeUp - JsonConfigInfo.configInfo.RangeDown)).ToString("F4"));
                        }

                        excelHelperCls.AddColumnDataFromCell(_excelFilePath, "数据", row, column + 4, result1);
                        excelHelperCls.AddColumnDataFromCell(_excelFilePath, "数据", row, column + 5, result2);
                    }
                }

                SerialPortsBase.PrintMessage("******************** 复测完成 ********************");
            }
            catch (Exception ex)
            {
                SerialPortsBase.PrintMessage(ex.Message);
                SerialPortsBase.PrintMessage("复测失败！");
            }
        }

        private void btnRetStop_Click(object sender, EventArgs e)
        {

        }

        private int GetStablizationPressureTimeSeconds()
        {
            int seconds = 0;

            string timeStr = cboxStabPreTime.Text;

            if (timeStr == "30秒")
            {
                seconds = 30;
            }
            else if (timeStr == "1分钟")
            {
                seconds = 60;
            }
            else if (timeStr == "2分钟")
            {
                seconds = 120;
            }
            else if (timeStr == "3分钟")
            {
                seconds = 180;
            }
            else if (timeStr == "4分钟")
            {
                seconds = 240;
            }
            else if (timeStr == "5分钟")
            {
                seconds = 300;
            }
            else if (timeStr == "6分钟")
            {
                seconds = 360;
            }
            else if (timeStr == "7分钟")
            {
                seconds = 420;
            }
            else if (timeStr == "8分钟")
            {
                seconds = 480;
            }
            else
            {
                seconds = 30;
            }

            return seconds;
        }

        private void InitExcel()
        {
            _excelFilePath = Path.Combine(_exePath, "result", txtBoxConfigSN.Text, $"{DateTime.Now:yyyMMdd_HHmm}_Retest.xlsx");
            excelHelperCls.CreateExcelFile(_excelFilePath);

            for (int i = 0; i < 4; i++)
            {
                List<string[]> tarnsducerID = new List<string[]>()
            {
                new string[] {
                    $"变送器{1 + i * 8}", "", "", "", "", "", "", $"变送器{2 + i * 8}", "", "", "", "", "", "",
                    $"变送器{3 + i * 8}", "", "", "", "", "", "", $"变送器{4 + i * 8}", "", "", "", "", "", "",
                    $"变送器{5 + i * 8}", "", "", "", "", "", "", $"变送器{6 + i * 8}", "", "", "", "", "", "",
                    $"变送器{7 + i * 8}", "", "", "", "", "", "", $"变送器{8 + i * 8}", "", "", "", "", "", "",
                }
            };
                excelHelperCls.AddRowsFromCell(_excelFilePath, "数据", 1 + i * 13, 1, tarnsducerID);
            }

            List<string[]> strings = new List<string[]>()
            {
                new string[] {
                    "上行程", "", "下行程","", "回差(PV)", "误差(%)", "",
                    "上行程", "", "下行程","", "回差(PV)", "误差(%)", "",
                    "上行程", "", "下行程","", "回差(PV)", "误差(%)", "",
                    "上行程", "", "下行程","", "回差(PV)", "误差(%)", "",
                    "上行程", "", "下行程","", "回差(PV)", "误差(%)", "",
                    "上行程", "", "下行程","", "回差(PV)", "误差(%)", "",
                    "上行程", "", "下行程","", "回差(PV)", "误差(%)", "",
                    "上行程", "", "下行程","", "回差(PV)", "误差(%)", "",
                },
            };
            excelHelperCls.AddRowsFromCell(_excelFilePath, "数据", 2, 1, strings);
            excelHelperCls.AddRowsFromCell(_excelFilePath, "数据", 15, 1, strings);
            excelHelperCls.AddRowsFromCell(_excelFilePath, "数据", 28, 1, strings);
            excelHelperCls.AddRowsFromCell(_excelFilePath, "数据", 41, 1, strings);

            excelHelperCls.ClrExcelDataBuffer();
        }

        private void button1_Click(object sender, EventArgs e)
        {

        }

        private async void btnPVZero_Click(object sender, EventArgs e)
        {
            bool bFlg = true;

            if (CommandsBase.bHasCMDExecuting == true)
            {
                SerialPortsBase.PrintMessage("有命令正在执行，请稍等！");
                return;
            }

            CommandsBase.bHasCMDExecuting = true;

            CloseAllPanelsIndicatorLight();

            List<(CMDsGroup, TimeSpan)> CMDsGroups = new List<(CMDsGroup, TimeSpan)>();

            BatchCaliBoardCMDsSwitchHARTChlCMD batchBoardSwitchChlCMD = new BatchCaliBoardCMDsSwitchHARTChlCMD(batchBoardSerialPort, "Traversal Switch Chl11");
            HART43SetPVZero PVZeroCmd = new HART43SetPVZero(hARTSerialPort_woyatechModem, "PV Zero");

            // RGB Alarm
            BatchCaliBoardCMDsSwitchRGB batchBoardSwitchRGB = new BatchCaliBoardCMDsSwitchRGB(batchBoardSerialPort, "Switch R Flashing", RGBSel.eRGB_G_Flashing);

            for (int i = 0; i < 32; i++)
            {
                if (gCheckBoxDevsSelectedAry[i].Checked)
                {
                    if (bFlg)
                    {
                        gCMSsGroupsAry[i].AddCommands(
                            new List<(CommandsBase, TimeSpan)>()
                            {
                                (batchBoardSwitchRGB, TimeSpan.FromSeconds(1)),
                                (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (PVZeroCmd, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            }
                        );

                        bFlg = false;
                    }
                    else
                    {
                        gCMSsGroupsAry[i].AddCommands(
                            new List<(CommandsBase, TimeSpan)>()
                            {
                                (batchBoardSwitchChlCMD, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                                (PVZeroCmd, TimeSpan.FromSeconds(_CommandsIntervalTimeSeconds)),
                            }
                        );
                    }

                    // callbacks
                    object[] args = new object[]
                    {
                        gIndicatorAry[i],
                    };
                    CMDsGroupManager.AddGroupsCallback(i + 1, UpdateIndicator, args);

                    CMDsGroups.Add((gCMSsGroupsAry[i], TimeSpan.FromSeconds(_GroupsIntervalTimeSeconds)));
                }
            }

            CMDsGroupManager.AddGroupsEndCallback(RGBStatusUpdGroupsEndCallback, new object[0]);

            CMDsGroupManager CMDsGroupsManager = new CMDsGroupManager(CMDsGroups);

            await CMDsGroupsManager.ExecuteAllGroupsAsync();
        }
    }
}
